/** * 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; struct api_msg msg; conn = netconn_alloc(t, callback); if (conn != NULL) { msg.function = do_newconn; msg.msg.msg.n.proto = proto; msg.msg.conn = conn; if (TCPIP_APIMSG(&msg) != ERR_OK) { LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); 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 */ sys_sem_free(&conn->op_completed); sys_mbox_free(&conn->recvmbox); memp_free(MEMP_NETCONN, conn); return NULL; } } return conn; }
/** Delete a semaphore * @param sem semaphore to delete */ void sys_sem_free(sys_sem_t *sem) { if (sys_sem_valid(sem)) { SYS_STATS_DEC(sem.used); vSemaphoreDelete(*sem); } }
/** * 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); #endif /* !LWIP_NETCONN_SEM_PER_THREAD */ sys_mbox_free(&conn->recvmbox); memp_free(MEMP_NETCONN, conn); return NULL; } } return conn; }
/** * \brief CGI request search engine. * * \param name CGI request name. * \param table CGI handler table. * \return A valid function handler for the specified CGI request, NULL otherwise. */ http_handler_t cgi_search(const char *name, HttpCGI *table) { /* Allocate the CGI semaphore. */ /* This is necessary to avoid race conditions on tx_buf.*/ if (!sys_sem_valid(&cgi_sem)) { sys_sem_new(&cgi_sem, 1); } if (!table) { return NULL; } int i = 0; const char *ext = get_ext(name); while (table[i].name) { if (ext && table[i].type == CGI_MATCH_EXT) { if (!strcmp(table[i].name, ext)) { break; } } else if (table[i].type == CGI_MATCH_NAME) { if (strstr(name, table[i].name) != NULL) { break; } } else { /* (table[i].type == CGI_MATCH_WORD) */ if (!strcmp(table[i].name, name)) { break; } } i++; } return table[i].handler; }
/** * 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 */ err_t tcpip_apimsg(struct api_msg *apimsg) { TCPIP_MSG_VAR_DECLARE(msg); #ifdef LWIP_DEBUG /* catch functions that don't set err */ apimsg->msg.err = ERR_VAL; #endif if (sys_mbox_valid_val(mbox)) { TCPIP_MSG_VAR_ALLOC(msg); TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; TCPIP_MSG_VAR_REF(msg).msg.apimsg = apimsg; #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 sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); sys_arch_sem_wait(LWIP_API_MSG_SEM(&apimsg->msg), 0); TCPIP_MSG_VAR_FREE(msg); return apimsg->msg.err; } return ERR_VAL; }
/** Wait for a semaphore for the specified timeout * @param sem the semaphore to wait for * @param timeout timeout in milliseconds to wait (0 = wait forever) * @return time (in milliseconds) waited for the semaphore * or SYS_ARCH_TIMEOUT on timeout */ u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) { TickType_t xStartTime, xEndTime, xElapsed; u32_t xReturn; if (!sys_sem_valid(sem)) { /** NON-VALID SEM */ return SYS_ARCH_TIMEOUT; } xStartTime = xTaskGetTickCount(); if( timeout != 0UL ) { if( xSemaphoreTake( *sem, timeout / portTICK_PERIOD_MS ) == pdTRUE ) { xEndTime = xTaskGetTickCount(); xElapsed = (xEndTime - xStartTime) * portTICK_PERIOD_MS; xReturn = xElapsed; } else { xReturn = SYS_ARCH_TIMEOUT; } } else { while( xSemaphoreTake( *sem, portMAX_DELAY ) != pdTRUE ); xEndTime = xTaskGetTickCount(); xElapsed = ( xEndTime - xStartTime ) * portTICK_PERIOD_MS; if( xElapsed == 0UL ) { xElapsed = 1UL; } xReturn = xElapsed; } return xReturn; }
/** * Sends a message to TCPIP thread to call a function. Caller thread blocks on * on a provided semaphore, which ist NOT automatically signalled by TCPIP thread, * this has to be done by the user. * It is recommended to use LWIP_TCPIP_CORE_LOCKING since this is the way * with least runtime overhead. * * @param fn function to be called from TCPIP thread * @param apimsg argument to API function * @param sem semaphore to wait on * @return ERR_OK if the function was called, another err_t if not */ err_t tcpip_send_msg_wait_sem(tcpip_callback_fn fn, void *apimsg, sys_sem_t* sem) { #if LWIP_TCPIP_CORE_LOCKING LWIP_UNUSED_ARG(sem); LOCK_TCPIP_CORE(); fn(apimsg); UNLOCK_TCPIP_CORE(); return ERR_OK; #else /* LWIP_TCPIP_CORE_LOCKING */ TCPIP_MSG_VAR_DECLARE(msg); LWIP_ASSERT("semaphore not initialized", sys_sem_valid(sem)); LWIP_ASSERT("Invalid mbox", sys_mbox_valid_val(mbox)); TCPIP_MSG_VAR_ALLOC(msg); TCPIP_MSG_VAR_REF(msg).type = TCPIP_MSG_API; TCPIP_MSG_VAR_REF(msg).msg.api_msg.function = fn; TCPIP_MSG_VAR_REF(msg).msg.api_msg.msg = apimsg; sys_mbox_post(&mbox, &TCPIP_MSG_VAR_REF(msg)); sys_arch_sem_wait(sem, 0); TCPIP_MSG_VAR_FREE(msg); return ERR_OK; #endif /* LWIP_TCPIP_CORE_LOCKING */ }
/** * Delete the pcb inside a netconn. * Called from netconn_delete. * * @param msg the api_msg_msg pointing to the connection */ void lwip_netconn_do_delconn(struct api_msg_msg *msg) { /* @todo TCP: abort running write/connect? */ if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN) && (msg->conn->state != NETCONN_CONNECT)) { /* this only happens for TCP netconns */ LWIP_ASSERT("NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP", NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP); msg->err = ERR_INPROGRESS; } else { LWIP_ASSERT("blocking connect in progress", (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); /* Drain and delete mboxes */ netconn_drain(msg->conn); if (msg->conn->pcb.tcp != NULL) { switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: raw_remove(msg->conn->pcb.raw); break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: msg->conn->pcb.udp->recv_arg = NULL; udp_remove(msg->conn->pcb.udp); break; #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && msg->conn->write_offset == 0); msg->conn->state = NETCONN_CLOSE; msg->msg.sd.shut = NETCONN_SHUT_RDWR; msg->conn->current_msg = msg; lwip_netconn_do_close_internal(msg->conn); /* API_EVENT is called inside lwip_netconn_do_close_internal, before releasing the application thread, so we can return at this point! */ return; #endif /* LWIP_TCP */ default: break; } msg->conn->pcb.tcp = NULL; } /* tcp netconns don't come here! */ /* @todo: this lets select make the socket readable and writable, which is wrong! errfd instead? */ API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); } if (sys_sem_valid(&msg->conn->op_completed)) { sys_sem_signal(&msg->conn->op_completed); } }
/** Signals a semaphore * @param sem the semaphore to signal */ void sys_sem_signal(sys_sem_t *sem) { portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE; if (sys_sem_valid(sem)) { if( exc_sense() ) { /** in interrupt */ xSemaphoreGiveFromISR( *sem, &xHigherPriorityTaskWoken ); } else { xSemaphoreGive( *sem ); } } }
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t count) { LWIP_ASSERT("invalid semaphor", sys_sem_valid(sem)); if (count != 0) { uint64_t stop, start; start = xtimer_now_usec64(); int res = sema_wait_timed((sema_t *)sem, count * US_PER_MS); stop = xtimer_now_usec64() - start; if (res == -ETIMEDOUT) { return SYS_ARCH_TIMEOUT; } return (u32_t)(stop / US_PER_MS); } else { sema_wait_timed((sema_t *)sem, 0); return 0; } }
/** Create a new semaphore * @param sem pointer to the semaphore to create * @param count initial count of the semaphore * @return ERR_OK if successful, another err_t otherwise */ err_t sys_sem_new(sys_sem_t *sem, u8_t count) { err_t ercd = ERR_MEM; vSemaphoreCreateBinary((*sem)); if (sys_sem_valid(sem)) { if (count == 0) { if (xSemaphoreTake(*sem, 1) == pdPASS) { ercd = ERR_OK; SYS_STATS_INC_USED(sem); } } else { ercd = ERR_OK; SYS_STATS_INC_USED(sem); } } else { SYS_STATS_INC(sem.err); } return ercd; }
void sys_sem_signal(sys_sem_t *sem) { LWIP_ASSERT("invalid semaphor", sys_sem_valid(sem)); sema_post((sema_t *)sem); }
/** * 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; }
void ethernetif_frame_ready() { EMAC_IntCmd(EMAC_INT_RX_DONE, DISABLE); if (sys_sem_valid(&sem_recv)) sys_sem_signal(&sem_recv); }