//This is the implementation of the UIPAPP that uIP will call when //something network data related happens. //The purpose of this app is to move buffer data to and from the network void uip_socket_app(void) { int i; file_handle_t file_handle = (uip_conn->appstate)[0]; struct file_t* file = NULL; struct buffer_t *rxbuf = NULL; struct buffer_t *txbuf = NULL; bool may_send = true; #ifdef __DEBUG printf("\r\napp: process conn @ %p", uip_conn); #endif if(uip_connected()) { #ifdef __DEBUG printf("\r\napp: connected. Ports %hd:%hd", uip_conn->lport, uip_conn->rport); #endif if( file_handle == FILE_INVALID_HANDLE ) { //it's an incoming connection (no assigned handle) //find the index of the listening port for( i = 0; i < UIP_LISTENPORTS ; i++ ) { if( uip_listenports[i] == uip_conn->lport ) { file_handle = listenports[i](uip_conn->lport, uip_conn->ripaddr, uip_conn->rport); if( file_handle != FILE_INVALID_HANDLE ) { uip_conn->appstate[0] = file_handle; } break; } } } } if( file_handle == FILE_INVALID_HANDLE) { goto close_or_abort; } file = file_get_by_handle(file_handle); rxbuf = file->read_buffer; txbuf = file->write_buffer; if( file->state == ClosePending ) { #ifdef __DEBUG printf("\r\napp: freeing handle %hhd",uip_conn->appstate[0]); #endif file_free(uip_conn->appstate[0]); uip_conn->appstate[0] = FILE_INVALID_HANDLE; goto close_or_abort; } if( rxbuf == NULL || txbuf == NULL ) { goto close_or_abort; } if( uip_connected() ) file->state = Open; if( uip_acked() ) { #ifdef __DEBUG printf("\r\napp: acked %d bytes", uip_this_ack); #endif buffer_seek( txbuf, uip_this_ack ); } int free = buffer_free( rxbuf );//free to write to int available = buffer_available( txbuf );//available to read if(uip_rexmit()) { //#ifdef __DEBUG printf("\r\napp: rexmit. Handle: %hhd", file_handle); //#endif buffer_peek( txbuf, (char*)uip_appdata, uip_conn->len); uip_send(uip_appdata, uip_conn->len); may_send = false; } else if(uip_newdata()) { #ifdef __DEBUG printf("\r\napp: newdata. Handle: %hhd. len=%u\n", file_handle, uip_datalen() ); #endif if( free >= uip_datalen() ) { free -= buffer_write( rxbuf, (char*)uip_appdata, uip_datalen() ); } else { puts("buffer overflow\n"); } } else if( uip_closed() ) { #ifdef __DEBUG printf("\r\napp: connection id %hhd closed\n", file_handle ); #endif file->state = Closed; may_send = false; } else if( uip_aborted() ) { #ifdef __DEBUG printf("\r\napp: connection id %hhd aborted\n", file_handle ); #endif file->state = Aborted; may_send = false; } else if( uip_timedout() ) { #ifdef __DEBUG printf("\r\napp: connection id %hhd timed out\n", file_handle ); #endif file->state = TimedOut; may_send = false; } // if( available > 0 && file->state > Open ) // { // buffer_seek( txbuf, available); // } if( available > 0 && may_send && uip_conn->len == 0) { //we can send the smaller of what's available or the connection mss int size = available < uip_mss() ? available : uip_mss() ; int peek = buffer_peek( txbuf, (char*)uip_appdata, size); uip_appdata[peek] = '\0'; #ifdef __DEBUG printf("\r\napp: sending %d of %d available bytes: [%s] ", peek,available, (char*)uip_appdata); #endif uip_send(uip_appdata, peek); } /* This code prevents the "silly-window" TCP problem The problem is though, that we want to fill our rx buffer entirely sometimes before acting on it. I've disabled this code in the meantime, until we can set the behaviour on a connection basis ...Or it becomes apparent that we just don't need it. if( free < rxbuf->size / 2 ) { puts("\napp: stopping rx\n"); uip_stop(); } else if( uip_stopped(uip_conn) ) { puts("\napp: restarting rx\n"); uip_restart(); //TODO NEED to be able to set the window size? } */ //...instead let's try setting the window size uip_receive_window = free; return; close_or_abort: if( uip_closed() || uip_aborted() || uip_timedout() ) { puts("\r\napp: abort chosen"); uip_abort(); } else { puts("\r\napp: close chosen"); uip_close(); } }
/*---------------------------------------------------------------------------*/ static PT_THREAD(handle_script(struct httpd_state *s)) { PGM_P ptr; PT_BEGIN(&s->scriptpt); while(s->file.len > 0) { /* Check if we should start executing a script. */ if(pgm_read_byte_near(s->file.data) == ISO_percent && pgm_read_byte_near(s->file.data + 1) == ISO_bang) { s->scriptptr = s->file.data + 3; s->scriptlen = s->file.len - 3; if(pgm_read_byte_near(s->scriptptr - 1) == ISO_colon) { strncpy_P(s->tmp_str, s->scriptptr + 1, sizeof(s->tmp_str) -1); if(httpd_fs_open(s->tmp_str, &s->file) || httpd_fs_open(s->tmp_str + 1 , &s->file)) { PT_WAIT_THREAD(&s->scriptpt, send_file(s)); } else { // could not open the file. } } else { strncpy_P(s->tmp_str, s->scriptptr, sizeof(s->tmp_str) -1); ((s->tmp_str)[sizeof(s->tmp_str) - 1]) = '\0'; PT_WAIT_THREAD(&s->scriptpt, httpd_cgi(s->tmp_str)(s, s->tmp_str)); } next_scriptstate(s); /* The script is over, so we reset the pointers and continue sending the rest of the file. */ s->file.data = s->scriptptr; s->file.len = s->scriptlen; } else { /* See if we find the start of script marker in the block of HTML to be sent. */ if(s->file.len > uip_mss()) { s->len = uip_mss(); } else { s->len = s->file.len; } if(pgm_read_byte_near(s->file.data) == ISO_percent) { ptr = strchr_P(s->file.data + 1, ISO_percent); } else { ptr = strchr_P(s->file.data, ISO_percent); } if(ptr != NULL && ptr != s->file.data) { s->len = (int)(ptr - s->file.data); if(s->len >= uip_mss()) { s->len = uip_mss(); } } PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s)); s->file.data += s->len; s->file.len -= s->len; } } PT_END(&s->scriptpt); /* PGM_P ptr; PT_BEGIN(&s->scriptpt); while(s->file.len > 0) { // Check if we should start executing a script. if( (pgm_read_byte(s->file.data) == ISO_percent) && (pgm_read_byte(s->file.data + 1) == ISO_bang)) { s->scriptptr = s->file.data + 3; s->scriptlen = s->file.len - 3; if(pgm_read_byte(s->scriptptr - 1) == ISO_colon) { strncpy_P(s->tmp_str, s->scriptptr + 1, sizeof(s->tmp_str) -1); if (httpd_fs_open(s->tmp_str, &s->file)) { PT_WAIT_THREAD(&s->scriptpt, send_file(s)); } } else { PT_WAIT_THREAD(&s->scriptpt, httpd_cgi(s->scriptptr)(s, s->scriptptr)); } next_scriptstate(s); // The script is over, so we reset the pointers and continue // sending the rest of the file. s->file.data = s->scriptptr; s->file.len = s->scriptlen; } else { // See if we find the start of script marker in the block of HTML // to be sent. if(s->file.len > uip_mss()) { s->len = uip_mss(); } else { s->len = s->file.len; } if(pgm_read_byte(s->file.data) == ISO_percent) { ptr = strchr_P(s->file.data + 1, ISO_percent); } else { ptr = strchr_P(s->file.data, ISO_percent); } if(ptr != NULL && ptr != s->file.data) { s->len = (int)(ptr - s->file.data); if(s->len >= uip_mss()) { s->len = uip_mss(); } } PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s)); s->file.data += s->len; s->file.len -= s->len; } } PT_END(&s->scriptpt); */ }
static uint16_t send_interrupt(FAR struct uip_driver_s *dev, FAR void *pvconn, FAR void *pvpriv, uint16_t flags) { FAR struct uip_conn *conn = (FAR struct uip_conn*)pvconn; FAR struct socket *psock = (FAR struct socket *)pvpriv; nllvdbg("flags: %04x\n", flags); /* If this packet contains an acknowledgement, then update the count of * acknowledged bytes. */ if ((flags & UIP_ACKDATA) != 0) { FAR sq_entry_t *entry, *next; FAR struct uip_wrbuffer_s *segment; uint32_t ackno; ackno = uip_tcpgetsequence(TCPBUF->ackno); for (entry = sq_peek(&conn->unacked_q); entry; entry = next) { next = sq_next(entry); segment = (FAR struct uip_wrbuffer_s*)entry; if (segment->wb_seqno < ackno) { nllvdbg("ACK: acked=%d buflen=%d ackno=%d\n", segment->wb_seqno, segment->wb_nbytes, ackno); /* Segment was ACKed. Remove from ACK waiting queue */ sq_rem(entry, &conn->unacked_q); /* Return the write buffer to the pool of free buffers */ uip_tcpwrbuffer_release(segment); } } } /* Check for a loss of connection */ else if ((flags & (UIP_CLOSE | UIP_ABORT | UIP_TIMEDOUT)) != 0) { /* Report not connected */ nllvdbg("Lost connection\n"); net_lostconnection(psock, flags); goto end_wait; } /* Check if we are being asked to retransmit data */ else if ((flags & UIP_REXMIT) != 0) { sq_entry_t *entry; /* Put all segments that have been sent but not ACKed to write queue * again note, the un-ACKed segment is put at the first of the write_q, * so it can be sent as soon as possible. */ while ((entry = sq_remlast(&conn->unacked_q))) { struct uip_wrbuffer_s *segment = (struct uip_wrbuffer_s*)entry; if (segment->wb_nrtx >= UIP_MAXRTX) { //conn->unacked -= segment->wb_nbytes; /* Return the write buffer */ uip_tcpwrbuffer_release(segment); /* NOTE expired is different from un-ACKed, it is designed to * represent the number of segments that have been sent, * retransmitted, and un-ACKed, if expired is not zero, the * connection will be closed. * * field expired can only be updated at UIP_ESTABLISHED state */ conn->expired++; continue; } send_insert_seqment(segment, &conn->write_q); } } /* Check if the outgoing packet is available (it may have been claimed * by a sendto interrupt serving a different thread). */ if (dev->d_sndlen > 0) { /* Another thread has beat us sending data, wait for the next poll */ return flags; } /* We get here if (1) not all of the data has been ACKed, (2) we have been * asked to retransmit data, (3) the connection is still healthy, and (4) * the outgoing packet is available for our use. In this case, we are * now free to send more data to receiver -- UNLESS the buffer contains * unprocesed incoming data. In that event, we will have to wait for the * next polling cycle. */ if ((conn->tcpstateflags & UIP_ESTABLISHED) && (flags & (UIP_POLL | UIP_REXMIT)) && !(sq_empty(&conn->write_q))) { /* Check if the destination IP address is in the ARP table. If not, * then the send won't actually make it out... it will be replaced with * an ARP request. * * NOTE 1: This could be an expensive check if there are a lot of * entries in the ARP table. * * NOTE 2: If we are actually harvesting IP addresses on incomming IP * packets, then this check should not be necessary; the MAC mapping * should already be in the ARP table. */ #if defined(CONFIG_NET_ETHERNET) && !defined(CONFIG_NET_ARP_IPIN) if (uip_arp_find(conn->ripaddr) != NULL) #endif { FAR struct uip_wrbuffer_s *segment; FAR void *sndbuf; size_t sndlen; /* Get the amount of data that we can send in the next packet */ segment = (FAR struct uip_wrbuffer_s *)sq_remfirst(&conn->write_q); if (segment) { sndbuf = segment->wb_buffer; sndlen = segment->wb_nbytes; DEBUGASSERT(sndlen <= uip_mss(conn)); /* REVISIT: There should be a check here to assure that we do * not excced the window (conn->winsize). */ /* Set the sequence number for this segment. NOTE: uIP * updates sndseq on receipt of ACK *before* this function * is called. In that case sndseq will point to the next * unacknowledged byte (which might have already been * sent). We will overwrite the value of sndseq here * before the packet is sent. */ if (segment->wb_nrtx == 0 && segment->wb_seqno == (unsigned)-1) { segment->wb_seqno = conn->isn + conn->sent; } uip_tcpsetsequence(conn->sndseq, segment->wb_seqno); /* Then set-up to send that amount of data. (this won't * actually happen until the polling cycle completes). */ uip_send(dev, sndbuf, sndlen); /* Remember how much data we send out now so that we know * when everything has been acknowledged. Just increment * the amount of data sent. This will be needed in * sequence* number calculations and we know that this is * not a re-transmission. Re-transmissions do not go through * this path. */ if (segment->wb_nrtx == 0) { conn->unacked += sndlen; conn->sent += sndlen; } /* Increment the retransmission counter before expiration. * NOTE we will not calculate the retransmission timer * (RTT) to save cpu cycles, each send_insert_seqment * segment will be retransmitted UIP_MAXRTX times in halt- * second interval before expiration. */ segment->wb_nrtx++; /* The segment is waiting for ACK again */ send_insert_seqment(segment, &conn->unacked_q); /* Only one data can be sent by low level driver at once, * tell the caller stop polling the other connection. */ flags &= ~UIP_POLL; } } } /* Continue waiting */ return flags; end_wait: /* Do not allow any further callbacks */ psock->s_sndcb->flags = 0; psock->s_sndcb->event = NULL; return flags; }
/*---------------------------------------------------------------------------*/ static unsigned short make_route(void *p) { static const char httpd_cgi_rtesh[] HTTPD_STRING_ATTR = " "; static const char httpd_cgi_rtes0[] HTTPD_STRING_ATTR = "<tr><td>"; static const char httpd_cgi_rtes1[] HTTPD_STRING_ATTR = "</td><td>%u</td><td>"; static const char httpd_cgi_rtes2[] HTTPD_STRING_ATTR = ", %lu s"; uint16_t numprinted; struct httpd_state *s = (struct httpd_state *)p; uip_ds6_route_t *r; // conn = &uip_conns[s->u.count]; numprinted = httpd_snprintf((char *)uip_appdata, uip_mss(), httpd_cgi_rtesh); if(numprinted >= uip_mss()) { return write_mss_error(11); } { r = s->u.ptr; /* <tr><td> */ numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_rtes0); if(numprinted >= uip_mss()) { return write_mss_error(12); } numprinted += httpd_cgi_sprint_ip6(&r->ipaddr, (char *)uip_appdata + numprinted); if(numprinted >= uip_mss()) { return write_mss_error(13); } uip_ds6_nbr_t *n; uip_ipaddr_t *nexthop; int nopath = 0; nexthop = uip_ds6_route_nexthop(r); n = uip_ds6_nbr_lookup(nexthop); if(r != NULL) { nopath = r->state.nopath_received; } numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_rtes1, nopath); if(numprinted >= uip_mss()) { return write_mss_error(14); } if(nexthop != NULL) { numprinted += httpd_cgi_sprint_ip6(nexthop, (char *)uip_appdata + numprinted); } if(numprinted >= uip_mss()) { return write_mss_error(15); } if(r->state.lifetime < 3600L * 24) { numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_rtes2, r->state.lifetime); if(numprinted >= uip_mss()) { return write_mss_error(16); } } /* Ping */ if(simple_udp_ping_has_reply(&r->ipaddr)) { int delay = simple_udp_ping_get_delay(&r->ipaddr); numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, "</td><td>%u ms", delay); if(numprinted >= uip_mss()) { return write_mss_error(6); } } else if(simple_udp_ping_has_sent(&r->ipaddr)) { numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, "</td><td>Ping scheduled..."); if(numprinted >= uip_mss()) { return write_mss_error(7); } } else { numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, "</td><td>-"); if(numprinted >= uip_mss()) { return write_mss_error(8); } } numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_addrb); if(numprinted >= uip_mss()) { return write_mss_error(9); } } return numprinted; }
// called for http server app void httpd_appcall(void){ struct fs_file fsfile; unsigned int i; switch(uip_conn->lport){ case HTONS(80): // app state hs = (struct httpd_state *)(uip_conn->appstate); // closed connection if(uip_closed()){ httpd_state_reset(); uip_close(); return; } // aborted connection or time out occured if(uip_aborted() || uip_timedout()){ httpd_state_reset(); uip_abort(); return; } // if we are pooled if(uip_poll()){ if(hs->count++ >= 100){ httpd_state_reset(); uip_abort(); } return; } // new connection if(uip_connected()){ httpd_state_reset(); return; } // new data in STATE_NONE if(uip_newdata() && hs->state == STATE_NONE){ // GET or POST request? if(uip_appdata[0] == ISO_G && uip_appdata[1] == ISO_E && uip_appdata[2] == ISO_T && (uip_appdata[3] == ISO_space || uip_appdata[3] == ISO_tab)){ hs->state = STATE_FILE_REQUEST; } else if(uip_appdata[0] == ISO_P && uip_appdata[1] == ISO_O && uip_appdata[2] == ISO_S && uip_appdata[3] == ISO_T && (uip_appdata[4] == ISO_space || uip_appdata[4] == ISO_tab)){ hs->state = STATE_UPLOAD_REQUEST; } // anything else -> abort the connection! if(hs->state == STATE_NONE){ httpd_state_reset(); uip_abort(); return; } // get file or firmware upload? if(hs->state == STATE_FILE_REQUEST){ // we are looking for GET file name for(i = 4; i < 30; i++){ if(uip_appdata[i] == ISO_space || uip_appdata[i] == ISO_cr || uip_appdata[i] == ISO_nl || uip_appdata[i] == ISO_tab){ uip_appdata[i] = 0; i = 0; break; } } if(i != 0){ printf("## Error: request file name too long!\n"); httpd_state_reset(); uip_abort(); return; } printf("Request for: "); printf("%s\n", &uip_appdata[4]); // request for / if(uip_appdata[4] == ISO_slash && uip_appdata[5] == 0){ fs_open(file_index_html.name, &fsfile); } else { // check if we have requested file if(!fs_open((const char *)&uip_appdata[4], &fsfile)){ printf("## Error: file not found!\n"); fs_open(file_404_html.name, &fsfile); } } hs->state = STATE_FILE_REQUEST; hs->dataptr = (u8_t *)fsfile.data; hs->upload = fsfile.len; // send first (and maybe the last) chunk of data uip_send(hs->dataptr, (hs->upload > uip_mss() ? uip_mss() : hs->upload)); return; } else if(hs->state == STATE_UPLOAD_REQUEST){ char *start = NULL; char *end = NULL; // end bufor data with NULL uip_appdata[uip_len] = '\0'; /* * We got first packet with POST request * * Some browsers don't include first chunk of data in the first * POST request packet (like Google Chrome, IE and Safari)! * So we must now find two values: * - Content-Length * - boundary * Headers with these values can be in any order! * If we don't find these values in first packet, connection will be aborted! * */ // Content-Length pos start = (char *)strstr((char*)uip_appdata, "Content-Length:"); if(start){ start += sizeof("Content-Length:"); // find end of the line with "Content-Length:" end = (char *)strstr(start, eol); if(end){ hs->upload_total = atoi(start); #ifdef DEBUG_UIP printf("Expecting %d bytes in body request message\n", hs->upload_total); #endif } else { printf("## Error: couldn't find \"Content-Length\"!\n"); httpd_state_reset(); uip_abort(); return; } } else { printf("## Error: couldn't find \"Content-Length\"!\n"); httpd_state_reset(); uip_abort(); return; } // we don't support very small files (< 10 KB) if(hs->upload_total < 10240){ printf("## Error: request for upload < 10 KB data!\n"); httpd_state_reset(); uip_abort(); return; } // boundary value start = NULL; end = NULL; start = (char *)strstr((char *)uip_appdata, "boundary="); if(start){ // move pointer over "boundary=" start += 9; // find end of line with boundary value end = (char *)strstr((char *)start, eol); if(end){ // malloc space for boundary value + '--' and '\0' boundary_value = (char*)malloc(end - start + 3); if(boundary_value){ memcpy(&boundary_value[2], start, end - start); // add -- at the begin and 0 at the end boundary_value[0] = '-'; boundary_value[1] = '-'; boundary_value[end - start + 2] = 0; #ifdef DEBUG_UIP printf("Found boundary value: \"%s\"\n", boundary_value); #endif } else { printf("## Error: couldn't allocate memory for boundary!\n"); httpd_state_reset(); uip_abort(); return; } } else { printf("## Error: couldn't find boundary!\n"); httpd_state_reset(); uip_abort(); return; } } else { printf("## Error: couldn't find boundary!\n"); httpd_state_reset(); uip_abort(); return; } /* * OK, if we are here, it means that we found * Content-Length and boundary values in headers * * We can now try to 'allocate memory' and * find beginning of the data in first packet */ webfailsafe_data_pointer = (u8_t *)WEBFAILSAFE_UPLOAD_RAM_ADDRESS; if(!webfailsafe_data_pointer){ printf("## Error: couldn't allocate RAM for data!\n"); httpd_state_reset(); uip_abort(); return; } else { printf("Data will be downloaded at 0x%X in RAM\n", WEBFAILSAFE_UPLOAD_RAM_ADDRESS); } if(httpd_findandstore_firstchunk()){ data_start_found = 1; } else { data_start_found = 0; } return; } /* else if(hs->state == STATE_UPLOAD_REQUEST) */ } /* uip_newdata() && hs->state == STATE_NONE */ // if we got ACK from remote host if(uip_acked()){ // if we are in STATE_FILE_REQUEST state if(hs->state == STATE_FILE_REQUEST){ // data which we send last time was received (we got ACK) // if we send everything last time -> gently close the connection if(hs->upload <= uip_mss()){ // post upload completed? if(webfailsafe_post_done){ if(!webfailsafe_upload_failed){ webfailsafe_ready_for_upgrade = 1; } webfailsafe_post_done = 0; webfailsafe_upload_failed = 0; } httpd_state_reset(); uip_close(); return; } // otherwise, send another chunk of data // last time we sent uip_conn->len size of data hs->dataptr += uip_conn->len; hs->upload -= uip_conn->len; uip_send(hs->dataptr, (hs->upload > uip_mss() ? uip_mss() : hs->upload)); } return; } // if we need to retransmit if(uip_rexmit()){ // if we are in STATE_FILE_REQUEST state if(hs->state == STATE_FILE_REQUEST){ // send again chunk of data without changing pointer and length of data left to send uip_send(hs->dataptr, (hs->upload > uip_mss() ? uip_mss() : hs->upload)); } return; } // if we got new data frome remote host if(uip_newdata()){ // if we are in STATE_UPLOAD_REQUEST state if(hs->state == STATE_UPLOAD_REQUEST){ // end bufor data with NULL uip_appdata[uip_len] = '\0'; // do we have to find start of data? if(!data_start_found){ if(!httpd_findandstore_firstchunk()){ printf("## Error: couldn't find start of data in next packet!\n"); httpd_state_reset(); uip_abort(); return; } else { data_start_found = 1; } return; } hs->upload += (unsigned int)uip_len; if(!webfailsafe_upload_failed){ memcpy((void *)webfailsafe_data_pointer, (void *)uip_appdata, uip_len); webfailsafe_data_pointer += uip_len; } httpd_download_progress(); // if we have collected all data if(hs->upload >= hs->upload_total){ printf("\n\n"); // end of post upload webfailsafe_post_done = 1; NetBootFileXferSize = (ulong)hs->upload_total; // which website will be returned if(!webfailsafe_upload_failed){ fs_open(file_flashing_html.name, &fsfile); } else { fs_open(file_fail_html.name, &fsfile); } httpd_state_reset(); hs->state = STATE_FILE_REQUEST; hs->dataptr = (u8_t *)fsfile.data; hs->upload = fsfile.len; uip_send(hs->dataptr, (hs->upload > uip_mss() ? uip_mss() : hs->upload)); } } return; } break; default: // we shouldn't get here... we are listening only on port 80 uip_abort(); break; } }
/*---------------------------------------------------------------------------*/ static unsigned short generate_file_stats(void *arg) { char *f = (char *)arg; return snprintf((char *)uip_appdata, uip_mss(), "%5u", httpd_fs_count(f)); }
/*---------------------------------------------------------------------------*/ static void appcall(void *state) { struct tcp_socket *s = state; if(s != NULL && s->c != NULL && s->c != uip_conn) { /* Safe-guard: this should not happen, as the incoming event relates to * a previous connection */ return; } if(uip_connected()) { /* Check if this connection originated in a local listen socket. We do this by checking the state pointer - if NULL, this is an incoming listen connection. If so, we need to connect the socket to the uip_conn and call the event function. */ if(s == NULL) { for(s = list_head(socketlist); s != NULL; s = list_item_next(s)) { if((s->flags & TCP_SOCKET_FLAGS_LISTENING) != 0 && s->listen_port != 0 && s->listen_port == uip_htons(uip_conn->lport)) { s->flags &= ~TCP_SOCKET_FLAGS_LISTENING; s->output_data_max_seg = uip_mss(); tcp_markconn(uip_conn, s); call_event(s, TCP_SOCKET_CONNECTED); break; } } } else { s->output_data_max_seg = uip_mss(); call_event(s, TCP_SOCKET_CONNECTED); } if(s == NULL) { uip_abort(); } else { if(uip_newdata()) { newdata(s); } senddata(s); } return; } if(uip_timedout()) { call_event(s, TCP_SOCKET_TIMEDOUT); relisten(s); } if(uip_aborted()) { tcp_markconn(uip_conn, NULL); call_event(s, TCP_SOCKET_ABORTED); relisten(s); } if(s == NULL) { uip_abort(); return; } if(uip_acked()) { acked(s); } if(uip_newdata()) { newdata(s); } if(uip_rexmit() || uip_newdata() || uip_acked()) { senddata(s); } else if(uip_poll()) { senddata(s); } if(s->output_data_len == 0 && s->flags & TCP_SOCKET_FLAGS_CLOSING) { s->flags &= ~TCP_SOCKET_FLAGS_CLOSING; uip_close(); s->c = NULL; tcp_markconn(uip_conn, NULL); s->c = NULL; /*call_event(s, TCP_SOCKET_CLOSED);*/ relisten(s); } if(uip_closed()) { tcp_markconn(uip_conn, NULL); s->c = NULL; call_event(s, TCP_SOCKET_CLOSED); relisten(s); } }
void xtcpd_appcall(void) { xtcpd_state_t *s; if (uip_udpconnection() && (uip_udp_conn->lport == HTONS(DHCPC_CLIENT_PORT) || uip_udp_conn->lport == HTONS(DHCPC_SERVER_PORT))) { #if UIP_USE_DHCP dhcpc_appcall(); #endif return; } if (uip_udpconnection()) { s = (xtcpd_state_t *) &(uip_udp_conn->appstate); if (uip_newdata()) { s->conn.remote_port = HTONS(UDPBUF->srcport); uip_ipaddr_copy(s->conn.remote_addr, BUF->srcipaddr); } } else if (uip_conn == NULL) { // dodgy uip_conn return; } else s = (xtcpd_state_t *) &(uip_conn->appstate); // if (!uip_udpconnection() && uip_connected()) { if (uip_connected()) { if (!uip_udpconnection()) { xtcpd_init_state(s, XTCP_PROTOCOL_TCP, (unsigned char *) uip_conn->ripaddr, uip_conn->lport, uip_conn->rport, uip_conn); xtcpd_event(XTCP_NEW_CONNECTION, s); } else { xtcpd_init_state(s, XTCP_PROTOCOL_UDP, (unsigned char *) uip_udp_conn->ripaddr, uip_udp_conn->lport, uip_udp_conn->rport, uip_udp_conn); xtcpd_event(XTCP_NEW_CONNECTION, s); } } if (uip_acked()) { int len; if (s->linknum != -1) { xtcpd_service_clients_until_ready(s->linknum, xtcp_links, xtcp_num); len = xtcpd_send(xtcp_links[s->linknum], XTCP_SENT_DATA, s, uip_appdata, uip_udpconnection() ? XTCP_CLIENT_BUF_SIZE : uip_mss()); if (len != 0) uip_send(uip_appdata, len); } } if (uip_newdata() && uip_len > 0) { if (s->linknum != -1) { if (!uip_udpconnection() && s->s.ack_recv_mode) { uip_stop(); } xtcpd_service_clients_until_ready(s->linknum, xtcp_links, xtcp_num); xtcpd_recv(xtcp_links, s->linknum, xtcp_num, s, uip_appdata, uip_datalen()); } } else if (uip_aborted()) { xtcpd_event(XTCP_ABORTED, s); return; } else if (uip_timedout()) { xtcpd_event(XTCP_TIMED_OUT, s); return; } if (uip_rexmit()) { int len; if (s->linknum != -1) { xtcpd_service_clients_until_ready(s->linknum, xtcp_links, xtcp_num); len = xtcpd_send(xtcp_links[s->linknum], XTCP_RESEND_DATA, s, uip_appdata, uip_udpconnection() ? XTCP_CLIENT_BUF_SIZE : uip_mss()); if (len != 0) uip_send(uip_appdata, len); } } if (uip_poll()) { uip_xtcpd_handle_poll(s); } if (uip_closed()) { if (!s->s.closed) { s->s.closed = 1; xtcpd_event(XTCP_CLOSED, s); } return; } }
void HttpDCall( uint8_t* pBuffer, uint16_t nBytes, struct tHttpD* pSocket) { uint16_t nBufSize; if (uip_connected()) { //Initialize this connection pSocket->pData = g_HtmlPageDefault; pSocket->nDataLeft = sizeof(g_HtmlPageDefault)-1; pSocket->nNewlines = 0; pSocket->nState = STATE_CONNECTED; pSocket->nPrevBytes = 0xFFFF; } else if (uip_newdata() || uip_acked()) { if (pSocket->nState == STATE_CONNECTED) { if (nBytes == 0) return; if (*pBuffer == 'G') pSocket->nState = STATE_GET_G; else if (*pBuffer == 'P') pSocket->nState = STATE_POST_P; nBytes--; pBuffer++; } if (pSocket->nState == STATE_GET_G) { if (nBytes == 0) return; if (*pBuffer == 'E') pSocket->nState = STATE_GET_GE; nBytes--; pBuffer++; } if (pSocket->nState == STATE_GET_GE) { if (nBytes == 0) return; if (*pBuffer == 'T') pSocket->nState = STATE_GET_GET; nBytes--; pBuffer++; } if (pSocket->nState == STATE_GET_GET) { if (nBytes == 0) return; if (*pBuffer == ' ') pSocket->nState = STATE_GOTGET; nBytes--; pBuffer++; } if (pSocket->nState == STATE_POST_P) { if (nBytes == 0) return; if (*pBuffer == 'O') pSocket->nState = STATE_POST_PO; nBytes--; pBuffer++; } if (pSocket->nState == STATE_POST_PO) { if (nBytes == 0) return; if (*pBuffer == 'S') pSocket->nState = STATE_POST_POS; nBytes--; pBuffer++; } if (pSocket->nState == STATE_POST_POS) { if (nBytes == 0) return; if (*pBuffer == 'T') pSocket->nState = STATE_POST_POST; nBytes--; pBuffer++; } if (pSocket->nState == STATE_POST_POST) { if (nBytes == 0) return; if (*pBuffer == ' ') pSocket->nState = STATE_GOTPOST; nBytes--; pBuffer++; } if (pSocket->nState == STATE_GOTPOST || pSocket->nState == STATE_GOTGET) { //Search for \r\n\r\n while (nBytes != 0) { if (*pBuffer == '\n') { pSocket->nNewlines++; } else if (*pBuffer == '\r') { } else { pSocket->nNewlines = 0; } pBuffer++; nBytes--; if (pSocket->nNewlines == 2) { //beginning found. if (pSocket->nState == STATE_GOTPOST) { //Initialize Parsing variables pSocket->nParseLeft = PARSEBYTES; pSocket->ParseState = PARSE_CMD; //start parsing pSocket->nState = STATE_PARSEPOST; } else if (pSocket->nState == STATE_GOTGET) { pSocket->nState = STATE_SENDHEADER; } break; } } } if (pSocket->nState == STATE_PARSEPOST) { while (nBytes--) { if (pSocket->ParseState == PARSE_CMD) { pSocket->ParseCmd = *pBuffer; pSocket->ParseState = PARSE_NUM10; } else if (pSocket->ParseState == PARSE_NUM10) { pSocket->ParseNum = (*pBuffer - '0') * 10; pSocket->ParseState = PARSE_NUM1; } else if (pSocket->ParseState == PARSE_NUM1) { pSocket->ParseNum += (*pBuffer - '0'); pSocket->ParseState = PARSE_EQUAL; } else if (pSocket->ParseState == PARSE_EQUAL) { pSocket->ParseState = PARSE_VAL; } else if (pSocket->ParseState == PARSE_VAL) { if (pSocket->ParseCmd == 'd') GpioSetDdr(pSocket->ParseNum, *pBuffer - '0'); else GpioSetPort(pSocket->ParseNum, *pBuffer - '0'); pSocket->ParseState = PARSE_DELIM; } else if (pSocket->ParseState == PARSE_DELIM) { pSocket->ParseState = PARSE_CMD; } pSocket->nParseLeft--; pBuffer++; if (pSocket->nParseLeft == 0) { //finished parsing pSocket->nState = STATE_SENDHEADER; break; } } } if (pSocket->nState == STATE_SENDHEADER) { uip_send(uip_appdata, CopyHttpHeader(uip_appdata, pSocket->nDataLeft)); pSocket->nState = STATE_SENDDATA; return; } if (pSocket->nState == STATE_SENDDATA) { //We have sent the HTML Header or HTML Data previously. //Now we send (further) Data depending on the Socket's pData pointer //If all data has been sent, we close the connection pSocket->nPrevBytes = pSocket->nDataLeft; nBufSize = CopyHttpData(uip_appdata, &pSocket->pData, &pSocket->nDataLeft, uip_mss()); pSocket->nPrevBytes -= pSocket->nDataLeft; if (nBufSize == 0) { //No Data has been copied. Close connection uip_close(); } else { //Else send copied data uip_send(uip_appdata, nBufSize); } return; } } else if (uip_rexmit()) { if (pSocket->nPrevBytes == 0xFFFF) { /* Send header again */ uip_send(uip_appdata, CopyHttpHeader(uip_appdata, pSocket->nDataLeft)); }else { pSocket->pData -= pSocket->nPrevBytes; pSocket->nDataLeft += pSocket->nPrevBytes; pSocket->nPrevBytes = pSocket->nDataLeft; nBufSize = CopyHttpData(uip_appdata, &pSocket->pData, &pSocket->nDataLeft, uip_mss()); pSocket->nPrevBytes -= pSocket->nDataLeft; if (nBufSize == 0) { //No Data has been copied. Close connection uip_close(); } else { //Else send copied data uip_send(uip_appdata, nBufSize); } } return; } }
/*-----------------------------------------------------------------------------------*/ DISPATCHER_UIPCALL(httpd_appcall, state) { struct httpd_fs_file fsfile; u8_t i; DISPATCHER_UIPCALL_ARG(state); hs = (struct httpd_state *)(state); /* We use the uip_ test functions to deduce why we were called. If uip_connected() is non-zero, we were called because a remote host has connected to us. If uip_newdata() is non-zero, we were called because the remote host has sent us new data, and if uip_acked() is non-zero, the remote host has acknowledged the data we previously sent to it. */ if(uip_connected()) { /* Since we've just been connected, the state pointer should be NULL and we need to allocate a new state object. If we have run out of memory for state objects, we'll have to abort the connection and return. */ if(hs == NULL) { hs = alloc_state(); if(hs == NULL) { uip_close(); return; } dispatcher_markconn(uip_conn, (void *)hs); } /* Since we have just been connected with the remote host, we reset the state for this connection. The ->count variable contains the amount of data that is yet to be sent to the remote host, and the ->state is set to HTTP_NOGET to signal that we haven't received any HTTP GET request for this connection yet. */ hs->state = HTTP_NOGET; hs->count = 0; hs->poll = 0; } else if(uip_closed() || uip_aborted()) { if(hs != NULL) { dealloc_state(hs); } return; } else if(uip_poll()) { /* If we are polled ten times, we abort the connection. This is because we don't want connections lingering indefinately in the system. */ if(hs != NULL) { if(hs->state == HTTP_DEALLOCATED) { uip_abort(); } else if(hs->poll++ >= 100) { uip_abort(); dealloc_state(hs); } } return; } if(uip_newdata() && hs->state == HTTP_NOGET) { hs->poll = 0; /* This is the first data we receive, and it should contain a GET. */ /* Check for GET. */ if(uip_appdata[0] != ISO_G || uip_appdata[1] != ISO_E || uip_appdata[2] != ISO_T || uip_appdata[3] != ISO_space) { /* If it isn't a GET, we abort the connection. */ uip_abort(); dealloc_state(hs); return; } beep(); /* Find the file we are looking for. */ for(i = 4; i < 40; ++i) { if(uip_appdata[i] == ISO_space || uip_appdata[i] == ISO_cr || uip_appdata[i] == ISO_nl) { uip_appdata[i] = 0; break; } } PRINT("request for file "); PRINTLN(&uip_appdata[4]); webserver_log_file(uip_conn->ripaddr, &uip_appdata[4]); /* Check for a request for "/". */ if(uip_appdata[4] == ISO_slash && uip_appdata[5] == 0) { httpd_fs_open(file_index_html.name, &fsfile); } else { if(!httpd_fs_open((const char *)&uip_appdata[4], &fsfile)) { PRINTLN("couldn't open file"); httpd_fs_open(file_404_html.name, &fsfile); } } if(uip_appdata[4] == ISO_slash && uip_appdata[5] == ISO_c && uip_appdata[6] == ISO_g && uip_appdata[7] == ISO_i && uip_appdata[8] == ISO_slash) { /* If the request is for a file that starts with "/cgi/", we prepare for invoking a script. */ hs->script = fsfile.data; next_scriptstate(); } else { hs->script = NULL; /* The web server is now no longer in the HTTP_NOGET state, but in the HTTP_FILE state since is has now got the GET from the client and will start transmitting the file. */ hs->state = HTTP_FILE; /* Point the file pointers in the connection state to point to the first byte of the file. */ hs->dataptr = fsfile.data; hs->count = fsfile.len; } } if(hs->state != HTTP_FUNC) { /* Check if the client (remote end) has acknowledged any data that we've previously sent. If so, we move the file pointer further into the file and send back more data. If we are out of data to send, we close the connection. */ if(uip_acked()) { hs->poll = 0; if(hs->count >= uip_mss()) { hs->count -= uip_mss(); hs->dataptr += uip_mss(); } else { hs->count = 0; } if(hs->count == 0) { if(hs->script != NULL) { next_scriptline(); next_scriptstate(); } else { uip_close(); dealloc_state(hs); } } } } if(hs->state == HTTP_FUNC) { /* Call the CGI function. */ #if 1 if(httpd_cgitab[hs->script[2] - ISO_a]()) { /* If the function returns non-zero, we jump to the next line in the script. */ next_scriptline(); next_scriptstate(); } #endif } if(hs->state != HTTP_FUNC && !uip_poll()) { hs->poll = 0; /* Send a piece of data, but not more than the MSS of the connection. */ uip_send(hs->dataptr, hs->count > uip_mss()? uip_mss(): hs->count); } /* Finally, return to uIP. Our outgoing packet will soon be on its way... */ }
void httpd_handle_solometer (void) { static int8_t i = 0; static uint8_t cont_send = 0, parsing = 0; uint16_t mss,page_size; static uip_ipaddr_t hostaddr, dnsserver; //char *buf; static uint16_t ppos; uint16_t lpos,wslen; uint8_t p_par,pct,send_packet,buf[64]; uip_gethostaddr(&hostaddr); #ifdef DNS_SUPPORT eeprom_restore(dns_server, &dnsserver, IPADDR_LEN); #endif #define NUM_PAR 16 PARAM p[NUM_PAR] = { {PR_U8,"%u",(uint8_t *)&hostaddr}, {PR_U8,"%u",((uint8_t *)&hostaddr)+1}, {PR_U8,"%u",((uint8_t *)&hostaddr)+2}, {PR_U8,"%u",((uint8_t *)&hostaddr)+3}, {PR_U8,"%u",&WRID[0]}, {PR_STRING,"%s",post_cookie}, {PR_STRING,"%s",post_hostname}, {PR_U8,"%u",(uint8_t *)&post_hostip}, {PR_U8,"%u",((uint8_t *)&post_hostip)+1}, {PR_U8,"%u",((uint8_t *)&post_hostip)+2}, {PR_U8,"%u",((uint8_t *)&post_hostip)+3}, {PR_STRING,"%s",post_scriptname}, {PR_U8,"%u",(uint8_t *)&dnsserver}, {PR_U8,"%u",((uint8_t *)&dnsserver)+1}, {PR_U8,"%u",((uint8_t *)&dnsserver)+2}, {PR_U8,"%u",((uint8_t *)&dnsserver)+3} }; //debug_printf("Handle_solometer called.\n"); mss = uip_mss(); if(mss > 400) mss = 400; wslen = strlen_P(website); if (uip_newdata()) { /* We've received new data (maybe even the first time). We'll receive something like this: GET /solometer[?...] */ /* Make sure it's zero-terminated, so we can safely use strstr */ char *ptr = (char *)uip_appdata; ptr[uip_len] = 0; //debug_printf("Newdata: ---------\n%s\n-----------\n",ptr); if(strncasecmp_P (uip_appdata, PSTR ("GET /solometer"),14) == 0) { //debug_printf("This is the GET request header...\n"); ptr = strstr_P (uip_appdata, PSTR("?")) + 1; if(!ptr || *ptr == 0) { //debug_printf("This is a request only. Send page.\n"); i = 0; } else { //debug_printf("This is a set operation. Parsing...\n"); i = solometer_parse(ptr); } //debug_printf("Setze Parsing auf 1.\n"); parsing = 1; } if (parsing == 1) { // Do not start answering until all packets have arrived //debug_printf("Parsing = 1\n"); ptr = strstr_P (uip_appdata, PSTR("\r\n\r\n")); if (ptr) { //debug_printf("Setze Parsing auf 2.\n"); parsing = 2; } else { //debug_printf("Double NL not found. Waiting...\n"); return; } } if (parsing == 2) { //debug_printf("Parsing = 2. Sende Antwort.\n"); PASTE_RESET (); if(i || mss < 200) { PASTE_P (httpd_header_500_smt); cont_send = 0; } else { page_size = wslen); for(i=0;i<NUM_PAR;i++) if(p[i].typ == PR_STRING) page_size += sprintf(buf,p[i].s2,p[i].s3); else page_size += sprintf(buf,p[i].s2,*(uint8_t *)p[i].s3); PASTE_P (p1); sprintf(uip_appdata+uip_len,"%u\n",page_size); PASTE_P (p2); cont_send = 1; ppos = 0; } //debug_printf("%d: %s\n",cont_send,uip_appdata); PASTE_SEND (); parsing = 0; return; } }
/*-----------------------------------------------------------------------------------*/ void httpd(void) { struct fs_file fsfile; u8_t i; switch(uip_conn->lport) { /* This is the web server: */ case htons(80): /* Pick out the application state from the uip_conn structure. */ hs = (struct httpd_state *)(uip_conn->appstate); /* We use the uip_ test functions to deduce why we were called. If uip_connected() is non-zero, we were called because a remote host has connected to us. If uip_newdata() is non-zero, we were called because the remote host has sent us new data, and if uip_acked() is non-zero, the remote host has acknowledged the data we previously sent to it. */ if(uip_connected()) { /* Since we have just been connected with the remote host, we reset the state for this connection. The ->count variable contains the amount of data that is yet to be sent to the remote host, and the ->state is set to HTTP_NOGET to signal that we haven't received any HTTP GET request for this connection yet. */ hs->state = HTTP_NOGET; hs->count = 0; /* Don't send any data in return; we wait for the HTTP request instead. */ uip_send(uip_appdata, 0); return; } else if(uip_poll()) { /* If we are polled ten times, we abort the connection. This is because we don't want connections lingering indefinately in the system. */ if(hs->count++ >= 10) { uip_abort(); } return; } else if(uip_newdata() && hs->state == HTTP_NOGET) { /* This is the first data we receive, and it should contain a GET. */ /* Check for GET. */ if(uip_appdata[0] != ISO_G || uip_appdata[1] != ISO_E || uip_appdata[2] != ISO_T || uip_appdata[3] != ISO_space) { /* If it isn't a GET, we abort the connection. */ uip_abort(); return; } /* Find the file we are looking for. */ for(i = 4; i < 40; ++i) { if(uip_appdata[i] == ISO_space || uip_appdata[i] == ISO_cr || uip_appdata[i] == ISO_nl) { uip_appdata[i] = 0; break; } } PRINT("request for file "); PRINTLN(&uip_appdata[4]); if(!fs_open((const char *)&uip_appdata[4], &fsfile)) { PRINTLN("couldn't open file"); fs_open(file_index_html.name, &fsfile); } if(uip_appdata[4] == ISO_slash && uip_appdata[5] == ISO_c && uip_appdata[6] == ISO_g && uip_appdata[7] == ISO_i && uip_appdata[8] == ISO_slash) { /* If the request is for a file that starts with "/cgi/", we prepare for invoking a script. */ hs->script = fsfile.data; next_scriptstate(); } else { hs->script = NULL; /* The web server is now no longer in the HTTP_NOGET state, but in the HTTP_FILE state since is has now got the GET from the client and will start transmitting the file. */ hs->state = HTTP_FILE; /* Point the file pointers in the connection state to point to the first byte of the file. */ hs->dataptr = fsfile.data; hs->count = fsfile.len; } } if(hs->state != HTTP_FUNC) { /* Check if the client (remote end) has acknowledged any data that we've previously sent. If so, we move the file pointer further into the file and send back more data. If we are out of data to send, we close the connection. */ if(uip_acked()) { if(hs->count >= uip_mss()) { hs->count -= uip_mss(); hs->dataptr += uip_mss(); } else { hs->count = 0; } if(hs->count == 0) { if(hs->script != NULL) { next_scriptline(); next_scriptstate(); } else { uip_close(); } } } } if(hs->state == HTTP_FUNC) { /* Call the CGI function. */ if(cgitab[hs->script[2] - ISO_a]()) { /* If the function returns non-zero, we jump to the next line in the script. */ next_scriptline(); next_scriptstate(); } } if(hs->state != HTTP_FUNC && !uip_poll()) { /* Send a piece of data, but not more than the MSS of the connection. */ uip_send(hs->dataptr, hs->count > uip_mss()? uip_mss(): hs->count); } /* Finally, return to uIP. Our outgoing packet will soon be on its way... */ return; default: /* Should never happen. */ uip_abort(); break; } }
static uint16_t send_interrupt(struct uip_driver_s *dev, void *pvconn, void *pvpriv, uint16_t flags) { struct uip_conn *conn = (struct uip_conn*)pvconn; struct send_s *pstate = (struct send_s *)pvpriv; nllvdbg("flags: %04x acked: %d sent: %d\n", flags, pstate->snd_acked, pstate->snd_sent); /* If this packet contains an acknowledgement, then update the count of * acknowldged bytes. */ if ((flags & UIP_ACKDATA) != 0) { /* The current acknowledgement number number is the (relative) offset * of the of the next byte needed by the receiver. The snd_isn is the * offset of the first byte to send to the receiver. The difference * is the number of bytes to be acknowledged. */ pstate->snd_acked = uip_tcpgetsequence(TCPBUF->ackno) - pstate->snd_isn; nllvdbg("ACK: acked=%d sent=%d buflen=%d\n", pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen); /* Have all of the bytes in the buffer been sent and acknowledged? */ if (pstate->snd_acked >= pstate->snd_buflen) { /* Yes. Then pstate->snd_buflen should hold the number of bytes * actually sent. */ goto end_wait; } /* No.. fall through to send more data if necessary */ } /* Check if we are being asked to retransmit data */ else if ((flags & UIP_REXMIT) != 0) { /* Yes.. in this case, reset the number of bytes that have been sent * to the number of bytes that have been ACKed. */ pstate->snd_sent = pstate->snd_acked; /* Fall through to re-send data from the last that was ACKed */ } /* Check for a loss of connection */ else if ((flags & (UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT)) != 0) { /* Report not connected */ nllvdbg("Lost connection\n"); pstate->snd_sent = -ENOTCONN; goto end_wait; } /* Check if the outgoing packet is available (it may have been claimed * by a sendto interrupt serving a different thread). */ #if 0 /* We can't really support multiple senders on the same TCP socket */ else if (dev->d_sndlen > 0) { /* Another thread has beat us sending data, wait for the next poll */ return flags; } #endif /* We get here if (1) not all of the data has been ACKed, (2) we have been * asked to retransmit data, (3) the connection is still healthy, and (4) * the outgoing packet is available for our use. In this case, we are * now free to send more data to receiver -- UNLESS the buffer contains * unprocessing incoming data. In that event, we will have to wait for the * next polling cycle. */ if ((flags & UIP_NEWDATA) == 0 && pstate->snd_sent < pstate->snd_buflen) { uint32_t seqno; /* Get the amount of data that we can send in the next packet */ uint32_t sndlen = pstate->snd_buflen - pstate->snd_sent; if (sndlen > uip_mss(conn)) { sndlen = uip_mss(conn); } /* Set the sequence number for this packet. NOTE: uIP updates * sndseq on recept of ACK *before* this function is called. In that * case sndseq will point to the next unacknowledge byte (which might * have already been sent). We will overwrite the value of sndseq * here before the packet is sent. */ seqno = pstate->snd_sent + pstate->snd_isn; nllvdbg("SEND: sndseq %08x->%08x\n", conn->sndseq, seqno); uip_tcpsetsequence(conn->sndseq, seqno); /* Then set-up to send that amount of data. (this won't actually * happen until the polling cycle completes). */ uip_send(dev, &pstate->snd_buffer[pstate->snd_sent], sndlen); /* Check if the destination IP address is in the ARP table. If not, * then the send won't actually make it out... it will be replaced with * an ARP request. * * NOTE 1: This could an expensive check if there are a lot of entries * in the ARP table. Hence, we only check on the first packet -- when * snd_sent is zero. * * NOTE 2: If we are actually harvesting IP addresses on incomming IP * packets, then this check should not be necessary; the MAC mapping * should already be in the ARP table. */ #if defined(CONFIG_NET_ETHERNET) && defined (CONFIG_NET_ARP_IPIN) if (pstate->snd_sent != 0 || uip_arp_find(conn->ripaddr) != NULL) #endif { /* Update the amount of data sent (but not necessarily ACKed) */ pstate->snd_sent += sndlen; nllvdbg("SEND: acked=%d sent=%d buflen=%d\n", pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen); /* Update the send time */ #if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) pstate->snd_time = clock_systimer(); #endif } } /* All data has been send and we are just waiting for ACK or re-transmit * indications to complete the send. Check for a timeout. */ #if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) else if (send_timeout(pstate)) { /* Yes.. report the timeout */ nlldbg("SEND timeout\n"); pstate->snd_sent = -ETIMEDOUT; goto end_wait; } #endif /* CONFIG_NET_SOCKOPTS && !CONFIG_DISABLE_CLOCK */ /* Continue waiting */ return flags; end_wait: /* Do not allow any further callbacks */ pstate->snd_cb->flags = 0; pstate->snd_cb->priv = NULL; pstate->snd_cb->event = NULL; /* There are no outstanding, unacknowledged bytes */ conn->unacked = 0; /* Wake up the waiting thread */ sem_post(&pstate->snd_sem); return flags; }
/*---------------------------------------------------------------------------*/ static unsigned short make_addrmap(void *p) { uint16_t numprinted; struct ip64_addrmap_entry *m; struct httpd_state *s = (struct httpd_state *)p; numprinted = 0; m = s->u.ptr; if(m != NULL && !timer_expired(&m->timer)) { numprinted += httpd_snprintf((char *)uip_appdata, uip_mss(), "<tr><td>"); if(numprinted >= uip_mss()) { return write_mss_error(20); } numprinted += httpd_cgi_sprint_ip6((uip_ipaddr_t *)&m->ip6addr, (char *)uip_appdata + numprinted); if(numprinted >= uip_mss()) { return write_mss_error(21); } numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, "</td><td>%d</td><td>", m->ip6port); if(numprinted >= uip_mss()) { return write_mss_error(22); } numprinted += httpd_sprint_ip4(&m->ip4addr, (char *)uip_appdata + numprinted); if(numprinted >= uip_mss()) { return write_mss_error(23); } numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, "</td><td>%d</td><td>%d</td>", m->ip4port, m->mapped_port); if(numprinted >= uip_mss()) { return write_mss_error(24); } numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, "<td>%d</td>", m->protocol); if(numprinted >= uip_mss()) { return write_mss_error(25); } numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, "<td>%lu</td>", m->timer.interval - (clock_time() - m->timer.start)); if(numprinted >= uip_mss()) { return write_mss_error(26); } numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, "<td>0x%02x</td>", m->flags); if(numprinted >= uip_mss()) { return write_mss_error(27); } } return numprinted; }
static PT_THREAD(handle_script(struct httpd_state *s)) { /* Note script includes will attach a leading : to the filename and a trailing zero */ static char scriptname[MAX_SCRIPT_NAME_LENGTH+1],*pptr; static uint16_t filelength; PT_BEGIN(&s->scriptpt); filelength=s->file.len; while(s->file.len > 0) { /* Sanity check */ if (s->file.len > filelength) break; /* Check if we should start executing a script, flagged by %! */ if(httpd_fs_getchar(s->file.data) == ISO_percent && httpd_fs_getchar(s->file.data + 1) == ISO_bang) { /* Extract name, if starts with colon include file else call cgi */ s->scriptptr=get_scriptname(scriptname,s->file.data+2); s->scriptlen=s->file.len-(s->scriptptr-s->file.data); PRINTF("httpd: Handle script named %s\n",scriptname); if(scriptname[0] == ISO_colon) { if (httpd_fs_open(&scriptname[1], &s->file)) { PT_WAIT_THREAD(&s->scriptpt, send_file(s)); } } else { PT_WAIT_THREAD(&s->scriptpt,httpd_cgi(scriptname)(s, s->scriptptr)); } next_scriptstate(s); /* Reset the pointers and continue sending the current file. */ s->file.data = s->scriptptr; s->file.len = s->scriptlen; } else { /* Send file up to the next potential script */ if(s->file.len > uip_mss()) { s->len = uip_mss(); } else { s->len = s->file.len; } if(httpd_fs_getchar(s->file.data) == ISO_percent) { pptr = (char *) httpd_fs_strchr(s->file.data + 1, ISO_percent); } else { pptr = (char *) httpd_fs_strchr(s->file.data, ISO_percent); } if(pptr != NULL && pptr != s->file.data) { s->len = (int)(pptr - s->file.data); if(s->len >= uip_mss()) { s->len = uip_mss(); } } PRINTF("httpd: Sending %u bytes from 0x%04x\n",s->file.len,(unsigned int)s->file.data); PT_WAIT_THREAD(&s->scriptpt, send_part_of_file(s)); s->file.data += s->len; s->file.len -= s->len; } } PT_END(&s->scriptpt); }
void TCPIP_TCPCallback(void) { if (uip_acked()) Debug_Print("[ACK] "); if (uip_newdata()) { Debug_Print("New Data:\r\n"); TCPIP_QueueData(uip_appdata, uip_datalen()); if (TCPIP_IsDataQueueFull()) uip_stop(); } if (uip_connected()) { Debug_Print("Connected - Maximum Segment Size: 0x"); Debug_PrintHex(uip_mss() / 256); Debug_PrintHex(uip_mss() & 255); Debug_Print("\r\n"); } if (uip_closed()) { Debug_Print("Closed - Reconnecting..."); _delay_ms(1000); ConnectedState = LINKMANAGEMENT_STATE_ConnectToRemoteHost; } if (uip_aborted()) { Debug_Print("Aborted - Reconnecting... "); _delay_ms(1000); ConnectedState = LINKMANAGEMENT_STATE_ConnectToRemoteHost; } if (uip_timedout()) { Debug_Print("Timeout - Reconnecting..."); uip_abort(); _delay_ms(1000); ConnectedState = LINKMANAGEMENT_STATE_ConnectToRemoteHost; } if (uip_poll() && (SystemTicks > 3000)) { SystemTicks = 0; Debug_Print("\r\nSending GET\r\n"); TCPIP_SendGET(); } if (uip_rexmit()) { Debug_Print("\r\nRetransmit GET\r\n"); TCPIP_SendGET(); } if (uip_poll() && uip_stopped(TCPConnection)) { if (!(TCPIP_IsDataQueueFull())) uip_restart(); } }
static void netTcpAppcallMutex(NetSock* sock) { if (uip_aborted()) { netAppcallClose(sock, NET_SOCK_PEER_ABORTED); } if (uip_timedout()) { netAppcallClose(sock, NET_SOCK_PEER_ABORTED); } if(uip_acked()) { if (sock->state == NET_SOCK_WRITING) { if (sock->len <= uip_mss()) { sock->len = 0; sock->state = NET_SOCK_WRITE_OK; posFlagSet(sock->uipChange, 0); } else { sock->buf = sock->buf + uip_mss(); sock->len -= uip_mss(); uip_send(sock->buf, sock->len); } } } if (uip_newdata()) { bool timeout = false; uint16_t dataLeft = uip_datalen(); char* dataPtr = uip_appdata; while (dataLeft > 0 && !timeout) { while (sock->state != NET_SOCK_READING && sock->state != NET_SOCK_READING_LINE && !timeout) { posMutexUnlock(sock->mutex); timeout = posFlagWait(sock->sockChange, MS(500)) == 0; posMutexLock(sock->mutex); } if (timeout) { // Timeout or bad state uip_abort(); netAppcallClose(sock, NET_SOCK_PEER_ABORTED); } else if (sock->state == NET_SOCK_READING_LINE) { char ch; while (dataLeft && sock->len < sock->max) { ch = *dataPtr; if (ch == '\r') { ++dataPtr; --dataLeft; continue; } sock->buf[sock->len] = ch; ++dataPtr; --dataLeft; ++sock->len; if (ch == '\n') break; } if (sock->len && (sock->len == sock->max || sock->buf[sock->len - 1] == '\n')) { sock->state = NET_SOCK_READ_OK; posFlagSet(sock->uipChange, 0); } } else if (sock->state == NET_SOCK_READING) { if (dataLeft > sock->max) sock->len = sock->max; else sock->len = dataLeft; memcpy(sock->buf, dataPtr, sock->len); dataLeft -= sock->len; dataPtr += sock->len; sock->state = NET_SOCK_READ_OK; posFlagSet(sock->uipChange, 0); } } } if (uip_rexmit()) { uip_send(sock->buf, sock->len); } if (uip_closed()) { netAppcallClose(sock, NET_SOCK_PEER_CLOSED); } if (uip_poll()) { if (sock->state == NET_SOCK_CLOSE) { uip_close(); netAppcallClose(sock, NET_SOCK_CLOSE_OK); } else if (sock->state == NET_SOCK_WRITING) { uip_send(sock->buf, sock->len); } } }
/* ----------------------------------------------------------------------------- * xtcpd_appcall * * this function is called, when a package comes in for an upper layer * application. * -------------------------------------------------------------------------- */ void xtcpd_appcall(void) { xtcpd_state_t *s; /* --------------- DHCP (v4) --------------- */ if (uip_udpconnection() && (uip_udp_conn->lport == HTONS(DHCPC_CLIENT_PORT) || uip_udp_conn->lport == HTONS(DHCPC_SERVER_PORT))) { #if UIP_USE_DHCP dhcpc_appcall(); #endif return; } /* --------- set up a new connection ---------- */ if (uip_udpconnection()){ s = (xtcpd_state_t *) &(uip_udp_conn->appstate); if (uip_newdata()) { // Set remote port to upper layer state s->conn.remote_port = HTONS(UDPBUF->srcport); uip_ipaddr_copy(s->conn.remote_addr.u8, BUF->srcipaddr.u8); } } else if (uip_conn == NULL) { // dodgy uip_conn return; } else { s = (xtcpd_state_t *) &(uip_conn->appstate); } /* ------ passing new connection event up to the upper xtcp layer ---- */ if (uip_connected()) { if (!uip_udpconnection()) { init_xtcpd_state(s, XTCP_PROTOCOL_TCP, *((xtcp_ipaddr_t *) (&uip_conn->ripaddr)), uip_conn->lport, uip_conn->rport, uip_conn); xtcpd_event(XTCP_NEW_CONNECTION, s); } else { init_xtcpd_state(s, XTCP_PROTOCOL_UDP, *((xtcp_ipaddr_t *) (&uip_udp_conn->ripaddr)), uip_udp_conn->lport, uip_udp_conn->rport, uip_udp_conn); xtcpd_event(XTCP_NEW_CONNECTION, s); } } /* --------------- new data event to deliver --------------- */ if (uip_newdata() && uip_len > 0) { if (s->linknum != -1) { xtcpd_service_clients_until_ready(s->linknum, xtcp_cons.links, xtcp_cons.nr); xtcpd_recv(xtcp_cons.links, s->linknum, xtcp_cons.nr, s, uip_appdata, uip_datalen()); if (!uip_udpconnection() && s->s.ack_recv_mode) { uip_stop(); } } } else if (uip_aborted()) { xtcpd_event(XTCP_ABORTED, s); return; } else if (uip_timedout()) { xtcpd_event(XTCP_TIMED_OUT, s); return; } /* ------------ passing acknowleg event to upper layer ------------- */ if (uip_acked()) { int len; if (s->linknum != -1) { len = do_xtcpd_send(xtcp_cons.links[s->linknum], XTCP_SENT_DATA, s, uip_appdata, uip_udpconnection() ? XTCP_CLIENT_BUF_SIZE : uip_mss()); uip_send(uip_appdata, len); } } /* -------------- retransmit the last package -------------- */ if (uip_rexmit()) { int len; if (s->linknum != -1) { xtcpd_service_clients_until_ready(s->linknum, xtcp_cons.links, xtcp_cons.nr); #ifdef XTCP_ENABLE_PARTIAL_PACKET_ACK s->conn.outstanding = 0; #endif len = xtcpd_send(xtcp_cons.links[s->linknum], XTCP_RESEND_DATA, s, uip_appdata, uip_udpconnection() ? XTCP_CLIENT_BUF_SIZE : uip_mss()); if (len != 0) uip_send(uip_appdata, len); } } /* --------------- poll a connection --------------- */ if (uip_poll()) { uip_xtcpd_handle_poll(s); } #if XTCP_ENABLE_PUSH_FLAG_NOTIFICATION if (uip_tcp_push()) { xtcpd_event(XTCP_PUSH_DATA, s); } #endif /* ------------- connection close event ------------ */ if (uip_closed()) { if (!s->s.closed){ s->s.closed = 1; xtcpd_event(XTCP_CLOSED, s); } return; } }
/*-----------------------------------------------------------------------------------*/ static void senddata(void) { register uint8_t *dataptr; uint16_t dataleft; dataptr = (uint8_t *)uip_appdata; switch(vs->sendmsg) { case VNC_SEND_VERSION: PRINTF(("Sending VERSION_STRING\n")); uip_send(RFB_SERVER_VERSION_STRING, sizeof(RFB_SERVER_VERSION_STRING)); break; case VNC_SEND_AUTH: /* Send 16 bytes of encrypted challange response. */ /* XXX: not implemented. */ PRINTF(("Sending AUTH\n")); uip_send(uip_appdata, 16); break; case VNC_SEND_CINIT: PRINTF(("Sending CINIT\n")); /* Send one byte of client init. */ *(uint8_t *)dataptr = 1; uip_send(uip_appdata, 1); break; case VNC_SEND_PFMT: PRINTF(("Sending PFMT\n")); ((struct rfb_set_pixel_format *)dataptr)->type = RFB_SET_PIXEL_FORMAT; /* Set to BGR233 pixel format. */ ((struct rfb_set_pixel_format *)dataptr)->format.bps = 8; ((struct rfb_set_pixel_format *)dataptr)->format.depth = 8; ((struct rfb_set_pixel_format *)dataptr)->format.endian = 1; ((struct rfb_set_pixel_format *)dataptr)->format.truecolor = 1; ((struct rfb_set_pixel_format *)dataptr)->format.red_max = uip_htons(7); ((struct rfb_set_pixel_format *)dataptr)->format.green_max = uip_htons(7); ((struct rfb_set_pixel_format *)dataptr)->format.blue_max = uip_htons(3); ((struct rfb_set_pixel_format *)dataptr)->format.red_shift = 0; ((struct rfb_set_pixel_format *)dataptr)->format.green_shift = 3; ((struct rfb_set_pixel_format *)dataptr)->format.blue_shift = 6; uip_send(uip_appdata, sizeof(struct rfb_set_pixel_format)); break; case VNC_SEND_ENCODINGS: PRINTF(("Sending ENCODINGS\n")); ((struct rfb_set_encodings *)dataptr)->type = RFB_SET_ENCODINGS; ((struct rfb_set_encodings *)dataptr)->encodings = uip_htons(1); dataptr += sizeof(struct rfb_set_encodings); dataptr[0] = dataptr[1] = dataptr[2] = 0; dataptr[3] = RFB_ENC_RAW; /* ((uint8_t *)dataptr + sizeof(struct rfb_set_encodings))[4] = ((uint8_t *)dataptr + sizeof(struct rfb_set_encodings))[5] = ((uint8_t *)dataptr + sizeof(struct rfb_set_encodings))[6] = 0; ((uint8_t *)dataptr + sizeof(struct rfb_set_encodings))[7] = RFB_ENC_RRE;*/ uip_send(uip_appdata, sizeof(struct rfb_set_encodings) + 4); break; case VNC_SEND_UPDATERQ: ((struct rfb_fb_update_request *)dataptr)->type = RFB_FB_UPDATE_REQ; ((struct rfb_fb_update_request *)dataptr)->incremental = 0; ((struct rfb_fb_update_request *)dataptr)->x = uip_htons(vnc_draw_viewport_x()); ((struct rfb_fb_update_request *)dataptr)->y = uip_htons(vnc_draw_viewport_y()); ((struct rfb_fb_update_request *)dataptr)->w = uip_htons(vnc_draw_viewport_w()); ((struct rfb_fb_update_request *)dataptr)->h = uip_htons(vnc_draw_viewport_h()); uip_send(uip_appdata, sizeof(struct rfb_fb_update_request)); break; case VNC_SEND_UPDATERQ_INC: ((struct rfb_fb_update_request *)dataptr)->type = RFB_FB_UPDATE_REQ; ((struct rfb_fb_update_request *)dataptr)->incremental = 1; ((struct rfb_fb_update_request *)dataptr)->x = uip_htons(vnc_draw_viewport_x()); ((struct rfb_fb_update_request *)dataptr)->y = uip_htons(vnc_draw_viewport_y()); ((struct rfb_fb_update_request *)dataptr)->w = uip_htons(vnc_draw_viewport_w()); ((struct rfb_fb_update_request *)dataptr)->h = uip_htons(vnc_draw_viewport_h()); uip_send(uip_appdata, sizeof(struct rfb_fb_update_request)); break; case VNC_SEND_EVENTS: dataleft = uip_mss(); vs->eventptr_unacked = vs->eventptr_acked; while(vs->eventptr_unacked != vs->eventptr_next && dataleft > sizeof(struct rfb_key_event)) { switch(vs->event_queue[vs->eventptr_unacked].type) { case VNC_POINTER_EVENT: ((struct rfb_pointer_event *)dataptr)->type = RFB_POINTER_EVENT; ((struct rfb_pointer_event *)dataptr)->buttonmask = vs->event_queue[vs->eventptr_unacked].ev.ptr.buttonmask; ((struct rfb_pointer_event *)dataptr)->x = uip_htons(vs->event_queue[vs->eventptr_unacked].ev.ptr.x); ((struct rfb_pointer_event *)dataptr)->y = uip_htons(vs->event_queue[vs->eventptr_unacked].ev.ptr.y); /* uip_send(uip_appdata, sizeof(struct rfb_pointer_event));*/ dataptr += sizeof(struct rfb_pointer_event); dataleft -= sizeof(struct rfb_pointer_event); break; case VNC_KEY_EVENT: PRINTF(("Send key event.\n")); ((struct rfb_key_event *)dataptr)->type = RFB_KEY_EVENT; ((struct rfb_key_event *)dataptr)->down = vs->event_queue[vs->eventptr_unacked].ev.key.down; ((struct rfb_key_event *)dataptr)->key[0] = ((struct rfb_key_event *)dataptr)->key[1]; ((struct rfb_key_event *)dataptr)->key[2] = vs->event_queue[vs->eventptr_unacked].ev.key.key >> 8; ((struct rfb_key_event *)dataptr)->key[3] = vs->event_queue[vs->eventptr_unacked].ev.key.key & 0xff; /* uip_send(uip_appdata, sizeof(struct rfb_key_event));*/ dataptr += sizeof(struct rfb_key_event); dataleft -= sizeof(struct rfb_key_event); break; case VNC_UPDATERQ_EVENT: ((struct rfb_fb_update_request *)dataptr)->type = RFB_FB_UPDATE_REQ; ((struct rfb_fb_update_request *)dataptr)->incremental = 0; ((struct rfb_fb_update_request *)dataptr)->x = uip_htons(vs->event_queue[vs->eventptr_unacked].ev.urq.x); ((struct rfb_fb_update_request *)dataptr)->y = uip_htons(vs->event_queue[vs->eventptr_unacked].ev.urq.y); ((struct rfb_fb_update_request *)dataptr)->w = uip_htons(vs->event_queue[vs->eventptr_unacked].ev.urq.w); ((struct rfb_fb_update_request *)dataptr)->h = uip_htons(vs->event_queue[vs->eventptr_unacked].ev.urq.h); /* uip_send(uip_appdata, sizeof(struct rfb_fb_update_request)); */ dataptr += sizeof(struct rfb_fb_update_request); dataleft -= sizeof(struct rfb_fb_update_request); break; } vs->eventptr_unacked = (vs->eventptr_unacked + 1) % VNC_EVENTQUEUE_SIZE; } uip_send(uip_appdata, uip_mss() - dataleft); break; } }
static uint16_t send_interrupt(FAR struct uip_driver_s *dev, FAR void *pvconn, FAR void *pvpriv, uint16_t flags) { FAR struct uip_conn *conn = (FAR struct uip_conn*)pvconn; FAR struct send_s *pstate = (FAR struct send_s *)pvpriv; nllvdbg("flags: %04x acked: %d sent: %d\n", flags, pstate->snd_acked, pstate->snd_sent); /* If this packet contains an acknowledgement, then update the count of * acknowledged bytes. */ if ((flags & UIP_ACKDATA) != 0) { /* Update the timeout */ #if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) pstate->snd_time = clock_systimer(); #endif /* The current acknowledgement number number is the (relative) offset * of the of the next byte needed by the receiver. The snd_isn is the * offset of the first byte to send to the receiver. The difference * is the number of bytes to be acknowledged. */ pstate->snd_acked = uip_tcpgetsequence(TCPBUF->ackno) - pstate->snd_isn; nllvdbg("ACK: acked=%d sent=%d buflen=%d\n", pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen); /* Have all of the bytes in the buffer been sent and acknowledged? */ if (pstate->snd_acked >= pstate->snd_buflen) { /* Yes. Then pstate->snd_buflen should hold the number of bytes * actually sent. */ goto end_wait; } /* No.. fall through to send more data if necessary */ } /* Check if we are being asked to retransmit data */ else if ((flags & UIP_REXMIT) != 0) { /* Yes.. in this case, reset the number of bytes that have been sent * to the number of bytes that have been ACKed. */ pstate->snd_sent = pstate->snd_acked; #if defined(CONFIG_NET_TCP_SPLIT) /* Reset the even/odd indicator to even since we need to * retransmit. */ pstate->snd_odd = false; #endif /* Fall through to re-send data from the last that was ACKed */ } /* Check for a loss of connection */ else if ((flags & (UIP_CLOSE|UIP_ABORT|UIP_TIMEDOUT)) != 0) { /* Report not connected */ nllvdbg("Lost connection\n"); net_lostconnection(pstate->snd_sock, flags); pstate->snd_sent = -ENOTCONN; goto end_wait; } /* Check if the outgoing packet is available (it may have been claimed * by a sendto interrupt serving a different thread). */ #if 0 /* We can't really support multiple senders on the same TCP socket */ else if (dev->d_sndlen > 0) { /* Another thread has beat us sending data, wait for the next poll */ return flags; } #endif /* We get here if (1) not all of the data has been ACKed, (2) we have been * asked to retransmit data, (3) the connection is still healthy, and (4) * the outgoing packet is available for our use. In this case, we are * now free to send more data to receiver -- UNLESS the buffer contains * unprocessed incoming data. In that event, we will have to wait for the * next polling cycle. */ if ((flags & UIP_NEWDATA) == 0 && pstate->snd_sent < pstate->snd_buflen) { uint32_t seqno; /* Get the amount of data that we can send in the next packet */ uint32_t sndlen = pstate->snd_buflen - pstate->snd_sent; #if defined(CONFIG_NET_TCP_SPLIT) /* RFC 1122 states that a host may delay ACKing for up to 500ms but * must respond to every second segment). This logic here will trick * the RFC 1122 recipient into responding sooner. This logic will be * activated if: * * 1. An even number of packets has been send (where zero is an even * number), * 2. There is more data be sent (more than or equal to * CONFIG_NET_TCP_SPLIT_SIZE), but * 3. Not enough data for two packets. * * Then we will split the remaining, single packet into two partial * packets. This will stimulate the RFC 1122 peer to ACK sooner. * * Don't try to split very small packets (less than CONFIG_NET_TCP_SPLIT_SIZE). * Only the first even packet and the last odd packets could have * sndlen less than CONFIG_NET_TCP_SPLIT_SIZE. The value of sndlen on * the last even packet is guaranteed to be at least MSS/2 by the * logic below. */ if (sndlen >= CONFIG_NET_TCP_SPLIT_SIZE) { /* sndlen is the number of bytes remaining to be sent. * uip_mss(conn) will return the number of bytes that can sent * in one packet. The difference, then, is the number of bytes * that would be sent in the next packet after this one. */ int32_t next_sndlen = sndlen - uip_mss(conn); /* Is this the even packet in the packet pair transaction? */ if (!pstate->snd_odd) { /* next_sndlen <= 0 means that the entire remaining data * could fit into this single packet. This is condition * in which we must do the split. */ if (next_sndlen <= 0) { /* Split so that there will be an odd packet. Here * we know that 0 < sndlen <= MSS */ sndlen = (sndlen / 2) + 1; } } /* No... this is the odd packet in the packet pair transaction */ else { /* Will there be another (even) packet afer this one? * (next_sndlen > 0) Will the split condition occur on that * next, even packet? ((next_sndlen - uip_mss(conn)) < 0) If * so, then perform the split now to avoid the case where the * byte count is less than CONFIG_NET_TCP_SPLIT_SIZE on the * next pair. */ if (next_sndlen > 0 && (next_sndlen - uip_mss(conn)) < 0) { /* Here, we know that sndlen must be MSS < sndlen <= 2*MSS * and so (sndlen / 2) is <= MSS. */ sndlen /= 2; } } } /* Toggle the even/odd indicator */ pstate->snd_odd ^= true; #endif /* CONFIG_NET_TCP_SPLIT */ if (sndlen > uip_mss(conn)) { sndlen = uip_mss(conn); } /* Check if we have "space" in the window */ if ((pstate->snd_sent - pstate->snd_acked + sndlen) < conn->winsize) { /* Set the sequence number for this packet. NOTE: uIP updates * sndseq on recept of ACK *before* this function is called. In that * case sndseq will point to the next unacknowledged byte (which might * have already been sent). We will overwrite the value of sndseq * here before the packet is sent. */ seqno = pstate->snd_sent + pstate->snd_isn; nllvdbg("SEND: sndseq %08x->%08x\n", conn->sndseq, seqno); uip_tcpsetsequence(conn->sndseq, seqno); /* Then set-up to send that amount of data. (this won't actually * happen until the polling cycle completes). */ uip_send(dev, &pstate->snd_buffer[pstate->snd_sent], sndlen); /* Check if the destination IP address is in the ARP table. If not, * then the send won't actually make it out... it will be replaced with * an ARP request. * * NOTE 1: This could be an expensive check if there are a lot of entries * in the ARP table. Hence, we only check on the first packet -- when * snd_sent is zero. * * NOTE 2: If we are actually harvesting IP addresses on incoming IP * packets, then this check should not be necessary; the MAC mapping * should already be in the ARP table. */ #if defined(CONFIG_NET_ETHERNET) && !defined(CONFIG_NET_ARP_IPIN) if (pstate->snd_sent != 0 || uip_arp_find(conn->ripaddr) != NULL) #endif { /* Update the amount of data sent (but not necessarily ACKed) */ pstate->snd_sent += sndlen; nllvdbg("SEND: acked=%d sent=%d buflen=%d\n", pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen); } } } /* All data has been sent and we are just waiting for ACK or re-transmit * indications to complete the send. Check for a timeout. */ #if defined(CONFIG_NET_SOCKOPTS) && !defined(CONFIG_DISABLE_CLOCK) if (send_timeout(pstate)) { /* Yes.. report the timeout */ nlldbg("SEND timeout\n"); pstate->snd_sent = -ETIMEDOUT; goto end_wait; } #endif /* CONFIG_NET_SOCKOPTS && !CONFIG_DISABLE_CLOCK */ /* Continue waiting */ return flags; end_wait: /* Do not allow any further callbacks */ pstate->snd_cb->flags = 0; pstate->snd_cb->priv = NULL; pstate->snd_cb->event = NULL; /* There are no outstanding, unacknowledged bytes */ conn->unacked = 0; /* Wake up the waiting thread */ sem_post(&pstate->snd_sem); return flags; }
/*---------------------------------------------------------------------------*/ static PT_THREAD( handle_script ( struct httpd_state *s ) ) { char *ptr; PT_BEGIN( &s->scriptpt ); ( void ) PT_YIELD_FLAG; while( s->file.len > 0 ) { /* Check if we should start executing a script. */ if( *s->file.data == ISO_percent && *(s->file.data + 1) == ISO_bang ) { s->scriptptr = s->file.data + 3; s->scriptlen = s->file.len - 3; if( *(s->scriptptr - 1) == ISO_colon ) { httpd_fs_open( s->scriptptr + 1, &s->file ); PT_WAIT_THREAD( &s->scriptpt, send_file(s) ); } else { PT_WAIT_THREAD( &s->scriptpt, httpd_cgi(s->scriptptr) (s, s->scriptptr) ); } next_scriptstate( s ); /* The script is over, so we reset the pointers and continue sending the rest of the file. */ s->file.data = s->scriptptr; s->file.len = s->scriptlen; } else { /* See if we find the start of script marker in the block of HTML to be sent. */ if( s->file.len > uip_mss() ) { s->len = uip_mss(); } else { s->len = s->file.len; } if( *s->file.data == ISO_percent ) { ptr = strchr( s->file.data + 1, ISO_percent ); } else { ptr = strchr( s->file.data, ISO_percent ); } if( ptr != NULL && ptr != s->file.data ) { s->len = ( int ) ( ptr - s->file.data ); if( s->len >= uip_mss() ) { s->len = uip_mss(); } } PT_WAIT_THREAD( &s->scriptpt, send_part_of_file(s) ); s->file.data += s->len; s->file.len -= s->len; } } PT_END( &s->scriptpt ); }
/*---------------------------------------------------------------------------*/ static unsigned short make_neighbor(void *p) { uint16_t numprinted = 0; uip_ds6_nbr_t *nbr; struct httpd_state *s = (struct httpd_state *)p; nbr = s->u.ptr; /* for(i = 0; i < UIP_DS6_NBR_NB; i++)*/ { /* if(uip_ds6_nbr_cache[i].isused)*/ { numprinted += httpd_snprintf((char *)uip_appdata, uip_mss(), httpd_cgi_addrh); if(numprinted >= uip_mss()) { return write_mss_error(4); } numprinted += httpd_cgi_sprint_ip6(&nbr->ipaddr, (char *)uip_appdata + numprinted); if(numprinted >= uip_mss()) { return write_mss_error(5); } if(simple_udp_ping_has_reply(&nbr->ipaddr)) { int delay = simple_udp_ping_get_delay(&nbr->ipaddr); numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, "</td><td>%u ms", delay); if(numprinted >= uip_mss()) { return write_mss_error(6); } } else if(simple_udp_ping_has_sent(&nbr->ipaddr)) { numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, "</td><td>Ping scheduled..."); if(numprinted >= uip_mss()) { return write_mss_error(7); } } else { numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, "</td><td>-"); if(numprinted >= uip_mss()) { return write_mss_error(8); } } numprinted += httpd_snprintf((char *)uip_appdata + numprinted, uip_mss() - numprinted, httpd_cgi_addrb); if(numprinted >= uip_mss()) { return write_mss_error(9); } } } return numprinted; }