/** Set back the timestamp of the last call to sys_check_timeouts() * This is necessary if sys_check_timeouts() hasn't been called for a long * time (e.g. while saving energy) to prevent all timer functions of that * period being called. */ void sys_restart_timeouts(void) { timeouts_last_time = sys_now(); }
/* Ping using the raw ip */ static u8_t ICACHE_FLASH_ATTR ping_recv(void *arg, struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *addr) { struct icmp_echo_hdr *iecho = NULL; static u16_t seqno = 0; struct ping_msg *pingmsg = (struct ping_msg*)arg; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(pcb); LWIP_UNUSED_ARG(addr); LWIP_ASSERT("p != NULL", p != NULL); if (pbuf_header( p, -PBUF_IP_HLEN)==0) { iecho = (struct icmp_echo_hdr *)p->payload; if ((iecho->id == PING_ID) && (iecho->seqno == htons(ping_seq_num)) && iecho->type == ICMP_ER) { LWIP_DEBUGF( PING_DEBUG, ("ping: recv ")); ip_addr_debug_print(PING_DEBUG, addr); LWIP_DEBUGF( PING_DEBUG, (" %"U32_F" ms\n", (sys_now()-ping_time))); if (iecho->seqno != seqno){ /* do some ping result processing */ { struct ip_hdr *iphdr = NULL; char ipaddrstr[16]; ip_addr_t source_ip; sys_untimeout(ping_timeout, pingmsg); os_bzero(&source_ip, sizeof(ip_addr_t)); os_bzero(ipaddrstr, sizeof(ipaddrstr)); uint32 delay = system_relative_time(pingmsg->ping_sent); delay /= PING_COARSE; iphdr = (struct ip_hdr*)((u8*)iecho - PBUF_IP_HLEN); source_ip.addr = iphdr->src.addr; ipaddr_ntoa_r(&source_ip,ipaddrstr, sizeof(ipaddrstr)); if (pingmsg->ping_opt->recv_function == NULL){ os_printf("recv %s: byte = %d, time = %d ms, seq = %d\n",ipaddrstr, PING_DATA_SIZE, delay, ntohs(iecho->seqno)); } else { struct ping_resp pingresp; os_bzero(&pingresp, sizeof(struct ping_resp)); pingresp.bytes = PING_DATA_SIZE; pingresp.resp_time = delay; pingresp.seqno = ntohs(iecho->seqno); pingresp.ping_err = 0; pingmsg->ping_opt->recv_function(pingmsg->ping_opt,(void*) &pingresp); } } seqno = iecho->seqno; } PING_RESULT(1); pbuf_free(p); return 1; /* eat the packet */ } // } else if(iecho->type == ICMP_ECHO){ // struct pbuf *q = NULL; // os_printf("receive ping request:seq=%d\n", ntohs(iecho->seqno)); // q = pbuf_alloc(PBUF_IP, (u16_t)p->tot_len, PBUF_RAM); // if (q!=NULL) { // pbuf_copy(q, p); // iecho = (struct icmp_echo_hdr *)q->payload; // ping_prepare_er(iecho, q->tot_len); // raw_sendto(pcb, q, addr); // pbuf_free(q); // } // pbuf_free(p); // return 1; // } } return 0; /* don't eat the packet */ }
/** * See if more data needs to be written from a previous call to netconn_write. * Called initially from lwip_netconn_do_write. If the first call can't send all data * (because of low memory or empty send-buffer), this function is called again * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the * blocking application thread (waiting in netconn_write) is released. * * @param conn netconn (that is currently in state NETCONN_WRITE) to process * @return ERR_OK * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished */ static err_t lwip_netconn_do_writemore(struct netconn *conn) { err_t err; void *dataptr; u16_t len, available; u8_t write_finished = 0; size_t diff; u8_t dontblock = netconn_is_nonblocking(conn) || (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK); u8_t apiflags = conn->current_msg->msg.w.apiflags; LWIP_ASSERT("conn != NULL", conn != NULL); LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", conn->write_offset < conn->current_msg->msg.w.len); #if LWIP_SO_SNDTIMEO if ((conn->send_timeout != 0) && ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) { write_finished = 1; if (conn->write_offset == 0) { /* nothing has been written */ err = ERR_WOULDBLOCK; conn->current_msg->msg.w.len = 0; } else { /* partial write */ err = ERR_OK; conn->current_msg->msg.w.len = conn->write_offset; } } else #endif /* LWIP_SO_SNDTIMEO */ { dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; diff = conn->current_msg->msg.w.len - conn->write_offset; if (diff > 0xffffUL) { /* max_u16_t */ len = 0xffff; #if LWIP_TCPIP_CORE_LOCKING conn->flags |= NETCONN_FLAG_WRITE_DELAYED; #endif apiflags |= TCP_WRITE_FLAG_MORE; } else { len = (u16_t)diff; } available = tcp_sndbuf(conn->pcb.tcp); if (available < len) { /* don't try to write more than sendbuf */ len = available; if (dontblock){ if (!len) { err = ERR_WOULDBLOCK; goto err_mem; } } else { #if LWIP_TCPIP_CORE_LOCKING conn->flags |= NETCONN_FLAG_WRITE_DELAYED; #endif apiflags |= TCP_WRITE_FLAG_MORE; } } LWIP_ASSERT("lwip_netconn_do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); /* if OK or memory error, check available space */ if ((err == ERR_OK) || (err == ERR_MEM)) { err_mem: if (dontblock && (len < conn->current_msg->msg.w.len)) { /* non-blocking write did not write everything: mark the pcb non-writable and let poll_tcp check writable space to mark the pcb writable again */ API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) { /* The queued byte- or pbuf-count exceeds the configured low-water limit, let select mark this pcb as non-writable. */ API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); } } if (err == ERR_OK) { conn->write_offset += len; if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) { /* return sent length */ conn->current_msg->msg.w.len = conn->write_offset; /* everything was written */ write_finished = 1; conn->write_offset = 0; } tcp_output(conn->pcb.tcp); } else if ((err == ERR_MEM) && !dontblock) { /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called we do NOT return to the application thread, since ERR_MEM is only a temporary error! */ /* tcp_write returned ERR_MEM, try tcp_output anyway */ tcp_output(conn->pcb.tcp); #if LWIP_TCPIP_CORE_LOCKING conn->flags |= NETCONN_FLAG_WRITE_DELAYED; #endif } else { /* On errors != ERR_MEM, we don't try writing any more but return the error to the application thread. */ write_finished = 1; conn->current_msg->msg.w.len = 0; } } if (write_finished) { /* everything was written: set back connection state and back to application task */ conn->current_msg->err = err; conn->current_msg = NULL; conn->state = NETCONN_NONE; #if LWIP_TCPIP_CORE_LOCKING if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0) #endif { sys_sem_signal(&conn->op_completed); } } #if LWIP_TCPIP_CORE_LOCKING else return ERR_MEM; #endif return ERR_OK; }
/** * Create a one-shot timer (aka timeout). Timeouts are processed in the * following cases: * - while waiting for a message using sys_timeouts_mbox_fetch() * - by calling sys_check_timeouts() (NO_SYS==1 only) * * @param msecs time in milliseconds after that the timer should expire * @param handler callback function to call when msecs have elapsed * @param arg argument to pass to the callback function */ #if LWIP_DEBUG_TIMERNAMES void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name) #else /* LWIP_DEBUG_TIMERNAMES */ void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) #endif /* LWIP_DEBUG_TIMERNAMES */ { struct sys_timeo *timeout, *t; #if NO_SYS u32_t now, diff; #endif timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); if (timeout == NULL) { LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); return; } #if NO_SYS now = sys_now(); if (next_timeout == NULL) { diff = 0; timeouts_last_time = now; } else { diff = now - timeouts_last_time; } #endif timeout->next = NULL; timeout->h = handler; timeout->arg = arg; #if NO_SYS timeout->time = msecs + diff; #else timeout->time = msecs; #endif #if LWIP_DEBUG_TIMERNAMES timeout->handler_name = handler_name; LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n", (void *)timeout, msecs, handler_name, (void *)arg)); #endif /* LWIP_DEBUG_TIMERNAMES */ if (next_timeout == NULL) { next_timeout = timeout; return; } if (next_timeout->time > msecs) { next_timeout->time -= msecs; timeout->next = next_timeout; next_timeout = timeout; } else { for (t = next_timeout; t != NULL; t = t->next) { timeout->time -= t->time; if (t->next == NULL || t->next->time > timeout->time) { if (t->next != NULL) { t->next->time -= timeout->time; } timeout->next = t->next; t->next = timeout; break; } } } }
/** * Call the lower part of a netconn_* function * This function is then running in the thread context * of tcpip_thread and has exclusive access to lwIP core code. * * @param apimsg a struct containing the function to call and its parameters * @return ERR_OK if the function was called, another err_t if not */ static err_t tcpip_apimsg(struct api_msg *apimsg) { #ifdef LWIP_DEBUG /* catch functions that don't set err */ apimsg->msg.err = ERR_VAL; #endif #if LWIP_NETCONN_SEM_PER_THREAD apimsg->msg.op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET(); LWIP_ASSERT("netconn semaphore not initialized", sys_sem_valid(apimsg->msg.op_completed_sem)); #endif #ifdef LWIP_ESP8266 //#if 0 sys_sem_t *op_sem_tmp = NULL; if(apimsg->function == lwip_netconn_do_write) op_sem_tmp = LWIP_API_MSG_SND_SEM(&apimsg->msg); else op_sem_tmp = LWIP_API_MSG_SEM(&apimsg->msg); if (tcpip_send_api_msg(apimsg->function, &apimsg->msg, op_sem_tmp) == ERR_OK) { #else if (tcpip_send_api_msg(apimsg->function, &apimsg->msg, LWIP_API_MSG_SEM(&apimsg->msg)) == ERR_OK) { #endif return apimsg->msg.err; } return ERR_VAL; } #endif /* !LWIP_TCPIP_CORE_LOCKING */ /** * Create a new netconn (of a specific type) that has a callback function. * The corresponding pcb is also created. * * @param t the type of 'connection' to create (@see enum netconn_type) * @param proto the IP protocol for RAW IP pcbs * @param callback a function to call on status changes (RX available, TX'ed) * @return a newly allocated struct netconn or * NULL on memory error */ struct netconn* netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) { struct netconn *conn; API_MSG_VAR_DECLARE(msg); conn = netconn_alloc(t, callback); if (conn != NULL) { err_t err; API_MSG_VAR_ALLOC_DONTFAIL(msg); API_MSG_VAR_REF(msg).msg.msg.n.proto = proto; API_MSG_VAR_REF(msg).msg.conn = conn; TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_newconn, err); API_MSG_VAR_FREE(msg); if (err != ERR_OK) { LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); #if LWIP_TCP LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); #endif /* LWIP_TCP */ #if !LWIP_NETCONN_SEM_PER_THREAD LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); sys_sem_free(&conn->op_completed); #ifdef LWIP_ESP8266 sys_sem_free(&conn->snd_op_completed); #endif #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ sys_mbox_free(&conn->recvmbox); memp_free(MEMP_NETCONN, conn); return NULL; } } return conn; } /** * Close a netconn 'connection' and free its resources. * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate * after this returns. * * @param conn the netconn to delete * @return ERR_OK if the connection was deleted */ err_t netconn_delete(struct netconn *conn) { err_t err; API_MSG_VAR_DECLARE(msg); /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ if (conn == NULL) { return ERR_OK; } API_MSG_VAR_ALLOC(msg); API_MSG_VAR_REF(msg).msg.conn = conn; #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER /* get the time we started, which is later compared to sys_now() + conn->send_timeout */ API_MSG_VAR_REF(msg).msg.msg.sd.time_started = sys_now(); #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ #if LWIP_TCP API_MSG_VAR_REF(msg).msg.msg.sd.polls_left = ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1; #endif /* LWIP_TCP */ #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */ TCPIP_APIMSG(&API_MSG_VAR_REF(msg), lwip_netconn_do_delconn, err); API_MSG_VAR_FREE(msg); if (err != ERR_OK) { return err; } netconn_free(conn); return ERR_OK; }
/** Receive data on an iperf tcp session */ static err_t lwiperf_tcp_recv(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err) { u8_t tmp; u16_t tot_len; u32_t packet_idx; struct pbuf* q; lwiperf_state_tcp_t* conn = (lwiperf_state_tcp_t*)arg; LWIP_ASSERT("pcb mismatch", conn->conn_pcb == tpcb); LWIP_UNUSED_ARG(tpcb); if (err != ERR_OK) { lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_REMOTE); return ERR_OK; } if (p == NULL) { /* connection closed -> test done */ if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) == PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST)) { /* client requested transmission after end of test */ lwiperf_tx_start(conn); } lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_SERVER); return ERR_OK; } tot_len = p->tot_len; conn->poll_count = 0; if ((!conn->have_settings_buf) || ((conn->bytes_transferred -24) % (1024*128) == 0)) { /* wait for 24-byte header */ if (p->tot_len < sizeof(lwiperf_settings_t)) { lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); pbuf_free(p); return ERR_VAL; } if (!conn->have_settings_buf) { if (pbuf_copy_partial(p, &conn->settings, sizeof(lwiperf_settings_t), 0) != sizeof(lwiperf_settings_t)) { lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL); pbuf_free(p); return ERR_VAL; } conn->have_settings_buf = 1; if ((conn->settings.flags & PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) == PP_HTONL(LWIPERF_FLAGS_ANSWER_TEST|LWIPERF_FLAGS_ANSWER_NOW)) { /* client requested parallel transmission test */ err_t err2 = lwiperf_tx_start(conn); if (err2 != ERR_OK) { lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_TXERROR); pbuf_free(p); return err2; } } } else { if (pbuf_memcmp(p, 0, &conn->settings, sizeof(lwiperf_settings_t)) != 0) { lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); pbuf_free(p); return ERR_VAL; } } conn->bytes_transferred += sizeof(lwiperf_settings_t); if (conn->bytes_transferred <= 24) { conn->time_started = sys_now(); tcp_recved(tpcb, p->tot_len); pbuf_free(p); return ERR_OK; } conn->next_num = 4; /* 24 bytes received... */ tmp = pbuf_header(p, -24); LWIP_ASSERT("pbuf_header failed", tmp == 0); } packet_idx = 0; for (q = p; q != NULL; q = q->next) { #if LWIPERF_CHECK_RX_DATA const u8_t* payload = (const u8_t*)q->payload; u16_t i; for (i = 0; i < q->len; i++) { u8_t val = payload[i]; u8_t num = val - '0'; if (num == conn->next_num) { conn->next_num++; if (conn->next_num == 10) { conn->next_num = 0; } } else { lwiperf_tcp_close(conn, LWIPERF_TCP_ABORTED_LOCAL_DATAERROR); pbuf_free(p); return ERR_VAL; } } packet_idx += i; #else packet_idx += q->len; #endif } LWIP_ASSERT("count mismatch", packet_idx == p->tot_len); conn->bytes_transferred += packet_idx; tcp_recved(tpcb, tot_len); pbuf_free(p); return ERR_OK; }
/* This is somewhat different to other ports: we have a main loop here: * a dedicated task that waits for packets to arrive. This would normally be * done from interrupt context with embedded hardware, but we don't get an * interrupt in windows for that :-) */ static void main_loop(void) { #if !NO_SYS err_t err; sys_sem_t init_sem; #endif /* NO_SYS */ #if USE_PPP #if !USE_ETHERNET int count; u8_t rxbuf[1024]; #endif volatile int callClosePpp = 0; #endif /* USE_PPP */ /* initialize lwIP stack, network interfaces and applications */ #if NO_SYS lwip_init(); test_init(NULL); #else /* NO_SYS */ err = sys_sem_new(&init_sem, 0); LWIP_ASSERT("failed to create init_sem", err == ERR_OK); tcpip_init(test_init, &init_sem); /* we have to wait for initialization to finish before * calling update_adapter()! */ sys_sem_wait(&init_sem); sys_sem_free(&init_sem); #endif /* NO_SYS */ #if (LWIP_SOCKET || LWIP_NETCONN) && LWIP_NETCONN_SEM_PER_THREAD netconn_thread_init(); #endif /* MAIN LOOP for driver update (and timers if NO_SYS) */ while (!_kbhit()) { #if NO_SYS /* handle timers (already done in tcpip.c when NO_SYS=0) */ sys_check_timeouts(); #endif /* NO_SYS */ #if USE_ETHERNET #if !PCAPIF_RX_USE_THREAD /* check for packets and link status*/ pcapif_poll(&netif); /* When pcapif_poll comes back, there are not packets, so sleep to prevent 100% CPU load. Don't do this in an embedded system since it increases latency! */ sys_msleep(1); #else /* !PCAPIF_RX_USE_THREAD */ sys_msleep(50); #endif /* !PCAPIF_RX_USE_THREAD */ #else /* USE_ETHERNET */ /* try to read characters from serial line and pass them to PPPoS */ count = sio_read(ppp_sio, (u8_t*)rxbuf, 1024); if(count > 0) { pppos_input(ppp, rxbuf, count); } else { /* nothing received, give other tasks a chance to run */ sys_msleep(1); } #endif /* USE_ETHERNET */ #if USE_SLIPIF slipif_poll(&slipif1); #if USE_SLIPIF > 1 slipif_poll(&slipif2); #endif /* USE_SLIPIF > 1 */ #endif /* USE_SLIPIF */ #if ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING /* check for loopback packets on all netifs */ netif_poll_all(); #endif /* ENABLE_LOOPBACK && !LWIP_NETIF_LOOPBACK_MULTITHREADING */ #if USE_PPP { int do_hup = 0; if(do_hup) { ppp_close(ppp, 1); do_hup = 0; } } if(callClosePpp && ppp) { /* make sure to disconnect PPP before stopping the program... */ callClosePpp = 0; #if NO_SYS ppp_close(ppp, 0); #else pppapi_close(ppp, 0); #endif ppp = NULL; } #endif /* USE_PPP */ } #if USE_PPP if(ppp) { u32_t started; printf("Closing PPP connection...\n"); /* make sure to disconnect PPP before stopping the program... */ #if NO_SYS ppp_close(ppp, 0); #else pppapi_close(ppp, 0); #endif ppp = NULL; /* Wait for some time to let PPP finish... */ started = sys_now(); do { #if USE_ETHERNET && !PCAPIF_RX_USE_THREAD pcapif_poll(&netif); #else /* USE_ETHERNET && !PCAPIF_RX_USE_THREAD */ sys_msleep(50); #endif /* USE_ETHERNET && !PCAPIF_RX_USE_THREAD */ /* @todo: need a better check here: only wait until PPP is down */ } while(sys_now() - started < 5000); } #endif /* USE_PPP */ #if (LWIP_SOCKET || LWIP_NETCONN) && LWIP_NETCONN_SEM_PER_THREAD netconn_thread_cleanup(); #endif #if USE_ETHERNET /* release the pcap library... */ pcapif_shutdown(&netif); #endif /* USE_ETHERNET */ }
/** Try to send more data on an iperf tcp session */ static err_t lwiperf_tcp_client_send_more(lwiperf_state_tcp_t* conn) { int send_more; err_t err; u16_t txlen; u16_t txlen_max; void* txptr; u8_t apiflags; LWIP_ASSERT("conn invalid", (conn != NULL) && conn->base.tcp && (conn->base.server == 0)); do { send_more = 0; if (conn->settings.amount & PP_HTONL(0x80000000)) { /* this session is time-limited */ u32_t now = sys_now(); u32_t diff_ms = now - conn->time_started; u32_t time = (u32_t)-(s32_t)htonl(conn->settings.amount); u32_t time_ms = time * 10; if (diff_ms >= time_ms) { /* time specified by the client is over -> close the connection */ lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT); return ERR_OK; } } else { /* this session is byte-limited */ u32_t amount_bytes = htonl(conn->settings.amount); /* @todo: this can send up to 1*MSS more than requested... */ if (amount_bytes >= conn->bytes_transferred) { /* all requested bytes transferred -> close the connection */ lwiperf_tcp_close(conn, LWIPERF_TCP_DONE_CLIENT); return ERR_OK; } } if (conn->bytes_transferred < 24) { /* transmit the settings a first time */ txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred]; txlen_max = (u16_t)(24 - conn->bytes_transferred); apiflags = TCP_WRITE_FLAG_COPY; } else if (conn->bytes_transferred < 48) { /* transmit the settings a second time */ txptr = &((u8_t*)&conn->settings)[conn->bytes_transferred - 24]; txlen_max = (u16_t)(48 - conn->bytes_transferred); apiflags = TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE; send_more = 1; } else { /* transmit data */ /* @todo: every x bytes, transmit the settings again */ txptr = (void*)(size_t)&lwiperf_txbuf_const[conn->bytes_transferred % 10]; txlen_max = TCP_MSS; if (conn->bytes_transferred == 48) { /* @todo: fix this for intermediate settings, too */ txlen_max = TCP_MSS - 24; } apiflags = 0; /* no copying needed */ send_more = 1; } txlen = txlen_max; do { err = tcp_write(conn->conn_pcb, txptr, txlen, apiflags); if (err == ERR_MEM) { txlen /= 2; } } while ((err == ERR_MEM) && (txlen >= (TCP_MSS/2))); if (err == ERR_OK) { conn->bytes_transferred += txlen; } else { send_more = 0; } } while(send_more); tcp_output(conn->conn_pcb); return ERR_OK; }
/** This is an example function that tests blocking- and nonblocking connect. */ static void sockex_nonblocking_connect(void *arg) { int s; int ret; u32_t opt; struct sockaddr_in addr; fdsets sets; struct timeval tv; u32_t ticks_a, ticks_b; int err; INIT_FDSETS(&sets); LWIP_UNUSED_ARG(arg); /* set up address to connect to */ memset(&addr, 0, sizeof(addr)); addr.sin_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = PP_HTONS(SOCK_TARGET_PORT); addr.sin_addr.s_addr = inet_addr(SOCK_TARGET_HOST); /* first try blocking: */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should succeed */ LWIP_ASSERT("ret == 0", ret == 0); /* write something */ ret = lwip_write(s, "test", 4); LWIP_ASSERT("ret == 4", ret == 4); /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); /* now try nonblocking and close before being connected */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* nonblocking */ opt = lwip_fcntl(s, F_GETFL, 0); LWIP_ASSERT("ret != -1", ret != -1); opt |= O_NONBLOCK; ret = lwip_fcntl(s, F_SETFL, opt); LWIP_ASSERT("ret != -1", ret != -1); /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should have an error: "inprogress" */ LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); /* try to close again, should fail with EBADF */ ret = lwip_close(s); LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EBADF", err == EBADF); printf("closing socket in nonblocking connect succeeded\n"); /* now try nonblocking, connect should succeed: this test only works if it is fast enough, i.e. no breakpoints, please! */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* nonblocking */ opt = 1; ret = lwip_ioctl(s, FIONBIO, &opt); LWIP_ASSERT("ret == 0", ret == 0); /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should have an error: "inprogress" */ LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); /* write should fail, too */ ret = lwip_write(s, "test", 4); LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); CHECK_FDSETS(&sets); FD_ZERO(&sets.readset); CHECK_FDSETS(&sets); FD_SET(s, &sets.readset); CHECK_FDSETS(&sets); FD_ZERO(&sets.writeset); CHECK_FDSETS(&sets); FD_SET(s, &sets.writeset); CHECK_FDSETS(&sets); FD_ZERO(&sets.errset); CHECK_FDSETS(&sets); FD_SET(s, &sets.errset); CHECK_FDSETS(&sets); tv.tv_sec = 0; tv.tv_usec = 0; /* select without waiting should fail */ ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, &tv); CHECK_FDSETS(&sets); LWIP_ASSERT("ret == 0", ret == 0); LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &sets.writeset)); LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset)); LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &sets.errset)); FD_ZERO(&sets.readset); FD_SET(s, &sets.readset); FD_ZERO(&sets.writeset); FD_SET(s, &sets.writeset); FD_ZERO(&sets.errset); FD_SET(s, &sets.errset); ticks_a = sys_now(); /* select with waiting should succeed */ ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, NULL); ticks_b = sys_now(); LWIP_ASSERT("ret == 1", ret == 1); LWIP_ASSERT("FD_ISSET(s, &writeset)", FD_ISSET(s, &sets.writeset)); LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset)); LWIP_ASSERT("!FD_ISSET(s, &errset)", !FD_ISSET(s, &sets.errset)); /* now write should succeed */ ret = lwip_write(s, "test", 4); LWIP_ASSERT("ret == 4", ret == 4); /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); printf("select() needed %d ticks to return writable\n", (int)(ticks_b - ticks_a)); /* now try nonblocking to invalid address: this test only works if it is fast enough, i.e. no breakpoints, please! */ /* create the socket */ s = lwip_socket(AF_INET, SOCK_STREAM, 0); LWIP_ASSERT("s >= 0", s >= 0); /* nonblocking */ opt = 1; ret = lwip_ioctl(s, FIONBIO, &opt); LWIP_ASSERT("ret == 0", ret == 0); addr.sin_addr.s_addr++; /* this should result in an invalid address */ /* connect */ ret = lwip_connect(s, (struct sockaddr*)&addr, sizeof(addr)); /* should have an error: "inprogress" */ LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); /* write should fail, too */ ret = lwip_write(s, "test", 4); LWIP_ASSERT("ret == -1", ret == -1); err = errno; LWIP_ASSERT("errno == EINPROGRESS", err == EINPROGRESS); FD_ZERO(&sets.readset); FD_SET(s, &sets.readset); FD_ZERO(&sets.writeset); FD_SET(s, &sets.writeset); FD_ZERO(&sets.errset); FD_SET(s, &sets.errset); tv.tv_sec = 0; tv.tv_usec = 0; /* select without waiting should fail */ ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, &tv); LWIP_ASSERT("ret == 0", ret == 0); FD_ZERO(&sets.readset); FD_SET(s, &sets.readset); FD_ZERO(&sets.writeset); FD_SET(s, &sets.writeset); FD_ZERO(&sets.errset); FD_SET(s, &sets.errset); ticks_a = sys_now(); /* select with waiting should eventually succeed and return errset! */ ret = lwip_select(s + 1, &sets.readset, &sets.writeset, &sets.errset, NULL); ticks_b = sys_now(); LWIP_ASSERT("ret > 0", ret > 0); LWIP_ASSERT("FD_ISSET(s, &errset)", FD_ISSET(s, &sets.errset)); /*LWIP_ASSERT("!FD_ISSET(s, &readset)", !FD_ISSET(s, &sets.readset)); LWIP_ASSERT("!FD_ISSET(s, &writeset)", !FD_ISSET(s, &sets.writeset));*/ /* close */ ret = lwip_close(s); LWIP_ASSERT("ret == 0", ret == 0); printf("select() needed %d ticks to return error\n", (int)(ticks_b - ticks_a)); printf("all tests done, thread ending\n"); }
/** * Create a new gprs connection * * @param device - Serial device number. */ gprs_t * gprs_new(u8_t device) { gprs_t * gprs; gprs = (gprs_t *) mem_malloc(sizeof(gprs_t)); if (gprs != 0) { LWIP_DEBUGF(GPRS_DEBUG,("gprs: new on device %d size %u\n",device,(unsigned)sizeof(gprs_t))); gprs->device = device; gprs->fd = sio_open(device); gprs->stateTime = sys_now(); #if GPRS_COMMAND_DELAY > 0 gprs->commandTime = gprs->stateTime; #endif gprs->imei[0] = 0; gprs->csq = GSM_CSQ_INVALID; if (gprs->fd != 0) { gprs->pcb = pppos_create(&gprs->pppif,gprs_pppos_output,gprs_callback,(void *)gprs); if (gprs->pcb) { gprs_set_state(gprs,GPRS_STATE_DISCONNECTED); #if GPRS_RUNTIME_APN gprs_set_apn(gprs,GPRS_APN); #endif #if GPRS_OWNTHREAD sys_sem_new(&gprs->recvSem,0); gprs->thread = sys_thread_new(GPRS_THREAD_NAME,gprs_thread,(void *)gprs,GPRS_THREAD_STACKSIZE,GPRS_THREAD_PRIO); #endif } else { LWIP_DEBUGF(GPRS_DEBUG,("gprs: pppos__create failed\n")); mem_free(gprs); gprs = (gprs_t *)0; } } else { LWIP_DEBUGF(GPRS_DEBUG,("gprs: _new failed sio_open(%d)\n",device)); mem_free(gprs); gprs = (gprs_t *)0; } } else { LWIP_DEBUGF(GPRS_DEBUG,("gprs: malloc failed\n")); } return gprs; }
/** * Return the number of milliseconds elapsed form the start of the current state. * * @return elapsed milliseconds. */ static u32_t gprs_state_elapsed(gprs_t * gprs) { return sys_now() - gprs->stateTime; }
/** * Check reply from the modem. * * @return 0 - No valid reply received * @return 1 - OK received * @return 2 - Error received. */ static int modem_check_reply(gprs_t * gprs,const u8_t *data,u32_t length,void (*callback)(gprs_t * gprs,const char *reply)) { u8_t c; int reply = MODEM_REPLY_NONE; while (length-- > 0 && reply == MODEM_REPLY_NONE) { c = *data++; switch (gprs->modem) { default: case MODEM_STATE_NONE: break; case MODEM_STATE_ECHO: if (gprs->sentCommand[gprs->modemCount] == c) { if (gprs->sentCommand[++gprs->modemCount] < 32) { modem_set_state(gprs,MODEM_STATE_WAITEOL); } } else { gprs->modemCount = 0; } break; case MODEM_STATE_WAITEOL: if (c < 32) { //LWIP_DEBUGF(GPRS_DEBUG,("Modem_check_reply: echo received\n")); modem_set_state(gprs,MODEM_STATE_REPLY); } break; case MODEM_STATE_REPLY: if (c < 32) { if (gprs->modemCount > 0) { gprs->replyBuffer[gprs->modemCount] = 0; LWIP_DEBUGF(MODEM_DEBUG,("gprs: Modem reply '%s'\n",gprs->replyBuffer)); gprs->modemCount = 0; if (!strcmp(gprs->replyBuffer,"OK")) { #if GPRS_COMMAND_DELAY > 0 gprs->commandTime = sys_now(); #endif //LWIP_DEBUGF(MODEM_DEBUG,("modem_check_reply: OK received\n")); reply = MODEM_REPLY_OK; } else if(!strncmp(gprs->replyBuffer,"ERROR",5)) { #if GPRS_COMMAND_DELAY > 0 gprs->commandTime = sys_now(); #endif LWIP_DEBUGF(MODEM_DEBUG,("gprs: Modem reply ERROR ERROR received\n")); reply = MODEM_REPLY_ERROR; } else { if (callback != 0) { (*callback)(gprs,gprs->replyBuffer); } } } } else { if (gprs->modemCount < sizeof(gprs->replyBuffer) - 1) { gprs->replyBuffer[gprs->modemCount++] = c; } else { LWIP_DEBUGF(GPRS_DEBUG,("gprs: GPRS_REPLY_BUFFER_SIZE too short")); } } break; } } return reply; }