コード例 #1
0
ファイル: sampleserver.c プロジェクト: kitnic/marmote
/*..........................................................................*/
static err_t server_accept(void					*arg,
							struct tcp_pcb		*pcb,
							err_t				err)
{
    struct server_state *hs;

    LWIP_UNUSED_ARG(arg);
    LWIP_UNUSED_ARG(err);

//    DEBUG_PRINT("server_accept 0x%08x\n", pcb);

    /* Allocate memory for the structure that holds the state of the
    connection. */
    hs = (struct server_state *)mem_malloc(sizeof(struct server_state));

    if (hs == NULL)
    {
//        DEBUG_PRINT("server_accept: Out of memory\n");
        return ERR_MEM;
    }

    /* Initialize the structure. */
    hs->file = NULL;
    hs->buf = NULL;
    hs->buf_len = 0;
    hs->left = 0;
    hs->retries = 0;


    /* Tell TCP that this is the structure we wish to be passed for our
    callbacks. */
    tcp_arg(pcb, hs);

    /* Tell TCP that we wish to be informed of incoming data by a call
    to the server_recv() function. */
    tcp_recv(pcb, server_recv);

    tcp_err(pcb, conn_err);

    tcp_poll(pcb, server_poll, 4);

//test begin

      appdata[0] = 'I';
      appdata[1] = 'S';
      appdata[2] = 'I';
      appdata[3] = 'S';
      appdata[4] = ' ';
      appdata[5] = ':';
      appdata[6] = ')';
      appdata[7] = ' ';
/*
      appdata[0] = 0xAA;
      appdata[1] = 0xAA;
      appdata[2] = 0xAA;
      appdata[3] = 0xAA;
      appdata[4] = 0xAA;
      appdata[5] = 0xAA;
      appdata[6] = 0xAA;
      appdata[7] = 0xAA;
*/
      hs->file = (char *)appdata;
      hs->left = 8;
      send_data(pcb, hs);
      // Tell TCP that we wish be to informed of data that has been
      //   successfully sent by a call to the http_sent() function.
      tcp_sent(pcb, server_sent);

//test end

    return ERR_OK;
}
コード例 #2
0
ファイル: espconn_tcp.c プロジェクト: FRANZEE/esp8266web
/******************************************************************************
 * FunctionName : espconn_tcp_client
 * Description  : Initialize the client: set up a connect PCB and bind it to
 *                the defined port
 * Parameters   : espconn -- the espconn used to build client
 * Returns      : none
*******************************************************************************/
sint8 ICACHE_FLASH_ATTR
espconn_tcp_client(struct espconn *espconn)
{
    struct tcp_pcb *pcb = NULL;
    struct ip_addr ipaddr;
    espconn_msg *pclient = NULL;

    /*Creates a new client control message*/
	pclient = (espconn_msg *)os_zalloc(sizeof(espconn_msg));
	if (pclient == NULL){
		return ESPCONN_MEM;
 	}

	/*Set an IP address given for Little-endian.*/
    IP4_ADDR(&ipaddr, espconn->proto.tcp->remote_ip[0],
    		espconn->proto.tcp->remote_ip[1],
    		espconn->proto.tcp->remote_ip[2],
    		espconn->proto.tcp->remote_ip[3]);

    /*Creates a new TCP protocol control block*/
    pcb = tcp_new();

    if (pcb == NULL) {
    	/*to prevent memory leaks, ensure that each allocated is deleted*/
    	os_free(pclient);
    	pclient = NULL;
        return ESPCONN_MEM;
    } else {

    	/*insert the node to the active connection list*/
    	espconn_list_creat(&plink_active, pclient);
    	tcp_arg(pcb, (void *)pclient);
    	tcp_err(pcb, espconn_client_err);
    	pclient->preverse = NULL;
    	pclient->pespconn = espconn;
    	pclient->pespconn->state = ESPCONN_WAIT;
    	pclient->pcommon.pcb = pcb;
    	tcp_bind(pcb, IP_ADDR_ANY, pclient->pespconn->proto.tcp->local_port);
#if 0
    	pclient->pcommon.err = tcp_bind(pcb, IP_ADDR_ANY, pclient->pespconn->proto.tcp->local_port);
    	if (pclient->pcommon.err != ERR_OK){
    		/*remove the node from the client's active connection list*/
    		espconn_list_delete(&plink_active, pclient);
    		memp_free(MEMP_TCP_PCB, pcb);
    		os_free(pclient);
    		pclient = NULL;
    		return ERR_USE;
    	}
#endif
        /*Establish the connection*/
        pclient->pcommon.err = tcp_connect(pcb, &ipaddr,
        		pclient->pespconn->proto.tcp->remote_port, espconn_client_connect);
        if (pclient->pcommon.err == ERR_RTE){
			/*remove the node from the client's active connection list*/
			espconn_list_delete(&plink_active, pclient);
			espconn_kill_pcb(pcb->local_port);
			os_free(pclient);
			pclient = NULL;
			return ESPCONN_RTE;
		}
        return pclient->pcommon.err;
    }
}
コード例 #3
0
ファイル: Network.cpp プロジェクト: DannyGH/RepRapFirmware
// Send some data or close this connection if we can, returning true if we can free up this object
bool RequestState::Send()
{
	if (LostConnection())
	{
		if (fileBeingSent != NULL)
		{
			fileBeingSent->Close();
			fileBeingSent = NULL;
		}
		return true;
	}

	if (hs->SendInProgress())
	{
		return false;
	}

	if (sentDataOutstanding != 0)
	{
		float timeNow = reprap.GetPlatform()->Time();
		if (timeNow - lastWriteTime > writeTimeout)
		{
			debugPrintf("Timing out connection hs=%08x\n", (unsigned int)hs);

			HttpState *locHs = hs;		// take a copy because our hs field is about to get cleared
			reprap.GetNetwork()->ConnectionClosing(locHs);
			tcp_pcb *pcb = locHs->pcb;
			tcp_arg(pcb, NULL);
			tcp_sent(pcb, NULL);
			tcp_recv(pcb, NULL);
			tcp_poll(pcb, NULL, 4);
			tcp_abort(pcb);
			mem_free(locHs);
			return false;				// this RS will be freed next time round
		}
	}

	if (sentDataOutstanding >= ARRAY_SIZE(outputBuffer)/2)
	{
		return false;	// don't send until at least half the output buffer is free
	}

	if (fileBeingSent != NULL)
	{
		unsigned int outputLimit = (sentDataOutstanding == 0)
				? ARRAY_SIZE(outputBuffer)
						: min<unsigned int>(unsentPointer + ARRAY_SIZE(outputBuffer)/2, ARRAY_SIZE(outputBuffer));

		while (outputPointer < outputLimit)
		{
			bool ok = fileBeingSent->Read(outputBuffer[outputPointer]);
			if (!ok)
			{
				fileBeingSent->Close();
				fileBeingSent = NULL;
				break;
			}
			++outputPointer;
		}
	}

	if (outputPointer == unsentPointer)
	{
		// We have no data to send. fileBeingSent must already be NULL here.
		if (!persistConnection && !closeRequested && nextWrite == NULL)
		{
			tcp_close(hs->pcb);
			closeRequested = true;
			// Don't release this RS yet, the write buffer may still be needed to do send retries
			return false;
		}

		if (sentDataOutstanding != 0)
		{
			return false;
		}

		// We've finished with this RS
		if (closeRequested)
		{
			// debugPrintf("Closing connection hs=%08x\n", (unsigned int)hs);

			HttpState *locHs = hs;		// take a copy because our hs field is about to get cleared
			reprap.GetNetwork()->ConnectionClosing(locHs);
			tcp_pcb *pcb = locHs->pcb;
			tcp_arg(pcb, NULL);
			tcp_sent(pcb, NULL);
			tcp_recv(pcb, NULL);
			tcp_poll(pcb, NULL, 4);
			mem_free(locHs);
		}
		return true;
	}
	else
	{
		sentDataOutstanding += (outputPointer - unsentPointer);
		RepRapNetworkSendOutput(outputBuffer + unsentPointer, outputPointer - unsentPointer, hs);
		unsentPointer = (outputPointer == ARRAY_SIZE(outputBuffer)) ? 0 : outputPointer;
		outputPointer = unsentPointer;
		lastWriteTime = reprap.GetPlatform()->Time();
		return false;
	}
}
コード例 #4
0
ファイル: tcp_echoclient.c プロジェクト: win95/TIS-RD
/* Connects to the TCP echo server */
err_t tcp_echoclient_connect(char* conn_name, uint8_t ip1, uint8_t ip2, uint8_t ip3, uint8_t ip4, uint16_t port, void* user_parameters) {
	struct ip_addr DestIPaddr;
	TM_TCPCLIENT_t* client;
	
	/* Check if we have already active connections */
	if (tcp_client_get_number_active_connections()) {
		/* If cable is unplugged and we want to make a new connection */
		if (CablePluggedWithActiveConnection) {
			/* Call user function if he wants to reset MCU */
			TM_ETHERNET_SystemResetCallback();
			
			/* Return "error" */
			return ERR_CONN;
		}
	}
	
	/* Check if conection name is too big */
	if (strlen(conn_name) >= ETHERNET_MAX_CONNECTION_NAME) {
		return ERR_ARG;
	}
	
	/* Check for connection */
	client = tcp_client_malloc();
	
	/* In case no memory available */
	if (client == NULL) {
		tcp_client_free(client);
		return ERR_MEM;
	}
	tcp_echoclient_connection_close(client,1);
	tcp_client_free(client);
	/* create new tcp pcb */
	client->pcb = tcp_new();
	
	if (client->pcb != NULL) {
		/* Set IP address */
		IP4_ADDR(&DestIPaddr, ip1, ip2, ip3, ip4);
		
		/* Save IP address */
		client->ip_addr[0] = ip1;
		client->ip_addr[1] = ip2;
		client->ip_addr[2] = ip3;
		client->ip_addr[3] = ip4;
		
		/* Save port */
		client->port = port;
		
		/* Clear flag for headers */
		client->headers_done = 0;
		
		/* Save user parameters */
		client->user_parameters = user_parameters;
		
		/* Save connection name */
		strcpy(client->name, conn_name);
		
		/* Set parameters */
		tcp_arg(client->pcb, client);
		
		/* Set error function */
		tcp_err(client->pcb, tcp_echoclient_error);
		
		/* connect to destination address/port */
		tcp_connect(client->pcb, &DestIPaddr, port, tcp_echoclient_connected);
		
		/* Connection has started */
		TM_ETHERNETCLIENT_ConnectionStartedCallback(client);
		
		/* Return OK */
		return ERR_OK;
	} else {
		/* Deallocate */
		tcp_client_free(client);
	}
	
	/* Return error */
	return ERR_CONN;
}
コード例 #5
0
ファイル: espconn_tcp.c プロジェクト: FRANZEE/esp8266web
/******************************************************************************
 * FunctionName : espconn_tcp_disconnect
 * Description  : disconnect with host
 * Parameters   : arg -- Additional argument to pass to the callback function
 * Returns      : none
*******************************************************************************/
static void ICACHE_FLASH_ATTR
espconn_tcp_disconnect_successful(void *arg)
{
	espconn_msg *pdiscon_cb = arg;
	sint8 dis_err = 0;
	espconn_buf *pdis_buf = NULL;
	espconn_buf *pdis_back = NULL;
	espconn_kill_oldest_pcb();
	if (pdiscon_cb != NULL) {
		struct espconn *espconn = pdiscon_cb->preverse;

		dis_err = pdiscon_cb->pcommon.err;
		if (pdiscon_cb->pespconn != NULL){
			struct tcp_pcb *pcb = NULL;
			if (espconn != NULL){/*Process the server's message block*/
				if (pdiscon_cb->pespconn->proto.tcp != NULL && espconn->proto.tcp){
					espconn_copy_partial(espconn, pdiscon_cb->pespconn);
					espconn_printf("server: %d.%d.%d.%d : %d disconnect\n", espconn->proto.tcp->remote_ip[0],
							espconn->proto.tcp->remote_ip[1],espconn->proto.tcp->remote_ip[2],
							espconn->proto.tcp->remote_ip[3],espconn->proto.tcp->remote_port);
					os_free(pdiscon_cb->pespconn->proto.tcp);
					pdiscon_cb->pespconn->proto.tcp = NULL;
				}
				os_free(pdiscon_cb->pespconn);
				pdiscon_cb->pespconn = NULL;
			} else {/*Process the client's message block*/
				espconn = pdiscon_cb->pespconn;
				espconn_printf("client: %d.%d.%d.%d : %d disconnect\n", espconn->proto.tcp->local_ip[0],
						espconn->proto.tcp->local_ip[1],espconn->proto.tcp->local_ip[2],
						espconn->proto.tcp->local_ip[3],espconn->proto.tcp->local_port);
			}
			/*process the current TCP block*/
			pcb = espconn_find_current_pcb(pdiscon_cb);
			if (pcb != NULL){
				if (espconn_reuse_disabled(pdiscon_cb)) {
					struct tcp_pcb *cpcb = NULL;
					struct tcp_pcb *prev = NULL;
					u8_t pcb_remove;
					espconn_printf("espconn_tcp_disconnect_successful %d, %d\n",	pcb->state, pcb->local_port);
					cpcb = tcp_tw_pcbs;
					while (cpcb != NULL) {
						pcb_remove = 0;
						if (cpcb->local_port == pcb->local_port) {
							++pcb_remove;
						}
						/* If the PCB should be removed, do it. */
						if (pcb_remove) {
							struct tcp_pcb *backup_pcb = NULL;
							tcp_pcb_purge(cpcb);
							/* Remove PCB from tcp_tw_pcbs list. */
							if (prev != NULL) {
								LWIP_ASSERT("espconn_tcp_delete: middle cpcb != tcp_tw_pcbs",cpcb != tcp_tw_pcbs);
								prev->next = cpcb->next;
							} else {
								/* This PCB was the first. */
								LWIP_ASSERT("espconn_tcp_delete: first cpcb == tcp_tw_pcbs",tcp_tw_pcbs == cpcb);
								tcp_tw_pcbs = cpcb->next;
							}
							backup_pcb = cpcb;
							cpcb = cpcb->next;
							memp_free(MEMP_TCP_PCB, backup_pcb);
						} else {
							prev = cpcb;
							cpcb = cpcb->next;
						}
					}

				} else {
					tcp_arg(pcb, NULL);
					tcp_err(pcb, NULL);
				}
			}
		}

		/*to prevent memory leaks, ensure that each allocated is deleted*/
		pdis_buf = pdiscon_cb->pcommon.pbuf;
		while (pdis_buf != NULL) {
			pdis_back = pdis_buf;
			pdis_buf = pdis_back->pnext;
			espconn_pbuf_delete(&pdiscon_cb->pcommon.pbuf, pdis_back);
			os_free(pdis_back);
			pdis_back = NULL;
		}
		os_bzero(&pktinfo[0], sizeof(struct espconn_packet));
		os_memcpy(&pktinfo[0], (void*)&pdiscon_cb->pcommon.packet_info, sizeof(struct espconn_packet));
		os_free(pdiscon_cb);
		pdiscon_cb = NULL;
		if (espconn->proto.tcp && espconn->proto.tcp->disconnect_callback != NULL) {
			espconn->proto.tcp->disconnect_callback(espconn);
		}
	} else {
		espconn_printf("espconn_tcp_disconnect err\n");
	}
}
コード例 #6
0
ファイル: api_msg.c プロジェクト: BlueSkyGjj/nRF52
/**
 * Receive callback function for RAW netconns.
 * Doesn't 'eat' the packet, only references it and sends it to
 * conn->recvmbox
 *
 * @see raw.h (struct raw_pcb.recv) for parameters and return value
 */
static u8_t
recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
    struct ip_addr *addr)
{
  struct pbuf *q;
  struct netbuf *buf;
  struct netconn *conn;
#if LWIP_SO_RCVBUF
  int recv_avail;
#endif /* LWIP_SO_RCVBUF */

  LWIP_UNUSED_ARG(addr);
  conn = arg;

#if LWIP_SO_RCVBUF
  SYS_ARCH_GET(conn->recv_avail, recv_avail);
  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) &&
      ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) {
#else  /* LWIP_SO_RCVBUF */
  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) {
#endif /* LWIP_SO_RCVBUF */
    /* copy the whole packet into new pbufs */
    q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
    if(q != NULL) {
      if (pbuf_copy(q, p) != ERR_OK) {
        pbuf_free(q);
        q = NULL;
      }
    }

    if(q != NULL) {
      buf = memp_malloc(MEMP_NETBUF);
      if (buf == NULL) {
        pbuf_free(q);
        return 0;
      }

      buf->p = q;
      buf->ptr = q;
      buf->addr = &(((struct ip_hdr*)(q->payload))->src);
      buf->port = pcb->protocol;

      SYS_ARCH_INC(conn->recv_avail, q->tot_len);
      /* Register event with callback */
      API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);
      if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
        netbuf_delete(buf);
      }
    }
  }

  return 0; /* do not eat the packet */
}
#endif /* LWIP_RAW*/

#if LWIP_UDP
/**
 * Receive callback function for UDP netconns.
 * Posts the packet to conn->recvmbox or deletes it on memory error.
 *
 * @see udp.h (struct udp_pcb.recv) for parameters
 */
static void
recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
   struct ip_addr *addr, u16_t port)
{
  struct netbuf *buf;
  struct netconn *conn;
#if LWIP_SO_RCVBUF
  int recv_avail;
#endif /* LWIP_SO_RCVBUF */

  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
  LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
  LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
  conn = arg;
  LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);

#if LWIP_SO_RCVBUF
  SYS_ARCH_GET(conn->recv_avail, recv_avail);
  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) ||
      ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
#else  /* LWIP_SO_RCVBUF */
  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
#endif /* LWIP_SO_RCVBUF */
    pbuf_free(p);
    return;
  }

  buf = memp_malloc(MEMP_NETBUF);
  if (buf == NULL) {
    pbuf_free(p);
    return;
  } else {
    buf->p = p;
    buf->ptr = p;
    buf->addr = addr;
    buf->port = port;
  }

  SYS_ARCH_INC(conn->recv_avail, p->tot_len);
  /* Register event with callback */
  API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);
  if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {
    netbuf_delete(buf);
    return;
  }
}
#endif /* LWIP_UDP */

#if LWIP_TCP
/**
 * Receive callback function for TCP netconns.
 * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
 *
 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
 */
static err_t
recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
  struct netconn *conn;
  u16_t len;

  LWIP_UNUSED_ARG(pcb);
  LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
  LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
  conn = arg;
  LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);

  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {
    return ERR_VAL;
  }

  conn->err = err;
  if (p != NULL) {
    len = p->tot_len;
    SYS_ARCH_INC(conn->recv_avail, len);
  } else {
    len = 0;
  }
  /* Register event with callback */
  API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
  if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {
    return ERR_MEM;
  }

  return ERR_OK;
}

/**
 * Poll callback function for TCP netconns.
 * Wakes up an application thread that waits for a connection to close
 * or data to be sent. The application thread then takes the
 * appropriate action to go on.
 *
 * Signals the conn->sem.
 * netconn_close waits for conn->sem if closing failed.
 *
 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
 */
static err_t
poll_tcp(void *arg, struct tcp_pcb *pcb)
{
  struct netconn *conn = arg;

  LWIP_UNUSED_ARG(pcb);
  LWIP_ASSERT("conn != NULL", (conn != NULL));

  if (conn->state == NETCONN_WRITE) {
    do_writemore(conn);
  } else if (conn->state == NETCONN_CLOSE) {
    do_close_internal(conn);
  }

  return ERR_OK;
}

/**
 * Sent callback function for TCP netconns.
 * Signals the conn->sem and calls API_EVENT.
 * netconn_write waits for conn->sem if send buffer is low.
 *
 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
 */
static err_t
sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
{
  struct netconn *conn = arg;

  LWIP_UNUSED_ARG(pcb);
  LWIP_ASSERT("conn != NULL", (conn != NULL));

  if (conn->state == NETCONN_WRITE) {
    LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
    do_writemore(conn);
  } else if (conn->state == NETCONN_CLOSE) {
    do_close_internal(conn);
  }

  if (conn) {
    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) {
      API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
    }
  }

  return ERR_OK;
}

/**
 * Error callback function for TCP netconns.
 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
 * The application thread has then to decide what to do.
 *
 * @see tcp.h (struct tcp_pcb.err) for parameters
 */
static void
err_tcp(void *arg, err_t err)
{
  struct netconn *conn;

  conn = arg;
  LWIP_ASSERT("conn != NULL", (conn != NULL));

  conn->pcb.tcp = NULL;

  conn->err = err;
  if (conn->recvmbox != SYS_MBOX_NULL) {
    /* Register event with callback */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
    sys_mbox_post(conn->recvmbox, NULL);
  }
  if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) {
    conn->state = NETCONN_NONE;
    sys_sem_signal(conn->op_completed);
  }
  if (conn->acceptmbox != SYS_MBOX_NULL) {
    /* Register event with callback */
    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
    sys_mbox_post(conn->acceptmbox, NULL);
  }
  if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {
    /* calling do_writemore/do_close_internal is not necessary
       since the pcb has already been deleted! */
    conn->state = NETCONN_NONE;
    /* wake up the waiting task */
    sys_sem_signal(conn->op_completed);
  }
}

/**
 * Setup a tcp_pcb with the correct callback function pointers
 * and their arguments.
 *
 * @param conn the TCP netconn to setup
 */
static void
setup_tcp(struct netconn *conn)
{
  struct tcp_pcb *pcb;

  pcb = conn->pcb.tcp;
  tcp_arg(pcb, conn);
  tcp_recv(pcb, recv_tcp);
  tcp_sent(pcb, sent_tcp);
  tcp_poll(pcb, poll_tcp, 4);
  tcp_err(pcb, err_tcp);
}

/**
 * Accept callback function for TCP netconns.
 * Allocates a new netconn and posts that to conn->acceptmbox.
 *
 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
 */
static err_t
accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
{
  struct netconn *newconn;
  struct netconn *conn;

#if API_MSG_DEBUG
#if TCP_DEBUG
  tcp_debug_print_state(newpcb->state);
#endif /* TCP_DEBUG */
#endif /* API_MSG_DEBUG */
  conn = (struct netconn *)arg;

  LWIP_ERROR("accept_function: invalid conn->acceptmbox",
             conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;);

  /* We have to set the callback here even though
   * the new socket is unknown. conn->socket is marked as -1. */
  newconn = netconn_alloc(conn->type, conn->callback);
  if (newconn == NULL) {
    return ERR_MEM;
  }
  newconn->pcb.tcp = newpcb;
  setup_tcp(newconn);
  newconn->err = err;
  /* Register event with callback */
  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);

  if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {
    /* When returning != ERR_OK, the connection is aborted in tcp_process(),
       so do nothing here! */
    newconn->pcb.tcp = NULL;
    netconn_free(newconn);
    return ERR_MEM;
  }
  return ERR_OK;
}
#endif /* LWIP_TCP */

/**
 * Create a new pcb of a specific type.
 * Called from do_newconn().
 *
 * @param msg the api_msg_msg describing the connection type
 * @return msg->conn->err, but the return value is currently ignored
 */
static err_t
pcb_new(struct api_msg_msg *msg)
{
   msg->conn->err = ERR_OK;

   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);

   /* Allocate a PCB for this connection */
   switch(NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
   case NETCONN_RAW:
     msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
     if(msg->conn->pcb.raw == NULL) {
       msg->conn->err = ERR_MEM;
       break;
     }
     raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
     break;
#endif /* LWIP_RAW */
#if LWIP_UDP
   case NETCONN_UDP:
     msg->conn->pcb.udp = udp_new();
     if(msg->conn->pcb.udp == NULL) {
       msg->conn->err = ERR_MEM;
       break;
     }
#if LWIP_UDPLITE
     if (msg->conn->type==NETCONN_UDPLITE) {
       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
     }
#endif /* LWIP_UDPLITE */
     if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
     }
     udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
     break;
#endif /* LWIP_UDP */
#if LWIP_TCP
   case NETCONN_TCP:
     msg->conn->pcb.tcp = tcp_new();
     if(msg->conn->pcb.tcp == NULL) {
       msg->conn->err = ERR_MEM;
       break;
     }
     setup_tcp(msg->conn);
     break;
#endif /* LWIP_TCP */
   default:
     /* Unsupported netconn type, e.g. protocol disabled */
     msg->conn->err = ERR_VAL;
     break;
   }

  return msg->conn->err;
}
コード例 #7
0
ファイル: api_msg.c プロジェクト: malooei/yeejoin-workspace
/**
 * Internal helper function to close a TCP netconn: since this sometimes
 * doesn't work at the first attempt, this function is called from multiple
 * places.
 *
 * @param conn the TCP netconn to close
 */
static void
do_close_internal(struct netconn *conn)
{
	err_t err;
	u8_t shut, shut_rx, shut_tx, close;

	LWIP_ASSERT("invalid conn", (conn != NULL));
	LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
	LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
	LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
	LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);

	shut = conn->current_msg->msg.sd.shut;
	shut_rx = shut & NETCONN_SHUT_RD;
	shut_tx = shut & NETCONN_SHUT_WR;
	/* shutting down both ends is the same as closing */
	close = shut == NETCONN_SHUT_RDWR;

	/* Set back some callback pointers */
	if (close) {
		tcp_arg(conn->pcb.tcp, NULL);
	}
	if (conn->pcb.tcp->state == LISTEN) {
		tcp_accept(conn->pcb.tcp, NULL);
	} else {
		/* some callbacks have to be reset if tcp_close is not successful */
		if (shut_rx) {
			tcp_recv(conn->pcb.tcp, NULL);
			tcp_accept(conn->pcb.tcp, NULL);
		}
		if (shut_tx) {
			tcp_sent(conn->pcb.tcp, NULL);
		}
		if (close) {
			tcp_poll(conn->pcb.tcp, NULL, 4);
			tcp_err(conn->pcb.tcp, NULL);
		}
	}
	/* Try to close the connection */
	if (shut == NETCONN_SHUT_RDWR) {
		err = tcp_close(conn->pcb.tcp);
	} else {
		err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR);
	}
	if (err == ERR_OK) {
		/* Closing succeeded */
		conn->current_msg->err = ERR_OK;
		conn->current_msg = NULL;
		conn->state = NETCONN_NONE;
		/* Set back some callback pointers as conn is going away */
		conn->pcb.tcp = NULL;
		/* Trigger select() in socket layer. Make sure everybody notices activity
		   on the connection, error first! */
		if (close) {
			API_EVENT(conn, NETCONN_EVT_ERROR, 0);
		}
		if (shut_rx) {
			API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
		}
		if (shut_tx) {
			API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
		}
		/* wake up the application task */
		sys_sem_signal(&conn->op_completed);
	} else {
		/* Closing failed, restore some of the callbacks */
		/* Closing of listen pcb will never fail! */
		LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN));
		tcp_sent(conn->pcb.tcp, sent_tcp);
		tcp_poll(conn->pcb.tcp, poll_tcp, 4);
		tcp_err(conn->pcb.tcp, err_tcp);
		tcp_arg(conn->pcb.tcp, conn);
		/* don't restore recv callback: we don't want to receive any more data */
	}
	/* If closing didn't succeed, we get called again either
	   from poll_tcp or from sent_tcp */
}
コード例 #8
0
//*****************************************************************************
//! Receives a TCP packet from lwIP for the telnet server.
//!
//! \param arg is the telnet state data for this connection.
//! \param pcb is the pointer to the TCP control structure.
//! \param p is the pointer to the pbuf structure containing the packet data.
//! \param err is used to indicate if any errors are associated with the
//! incoming packet.
//!
//! This function is called when the lwIP TCP/IP stack has an incoming packet
//! to be processed.
//!
//! \return This function will return an lwIP defined error code.
//*****************************************************************************
err_t TelnetReceive(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
    tState *pState = arg;
    SYS_ARCH_DECL_PROTECT(lev);

#if 0
    CONSOLE("%u: receive 0x%08x, 0x%08x, 0x%08x, %d\n", pState->ucSerialPort, arg, pcb, p, err);
#else
    CONSOLE("%u: receive error=%d\n", pState->ucSerialPort, err);
#endif

    // Place the incoming packet onto the queue if there is space.
    if((err == ERR_OK) && (p != NULL))
    {
        // This should be done in a protected/critical section.
        SYS_ARCH_PROTECT(lev);

        // Do we have space in the queue?
        int iNextWrite = ((pState->iBufQWrite + 1) % PBUF_POOL_SIZE);
        if(iNextWrite == pState->iBufQRead)
        {
            // The queue is full - discard the pbuf and return since we can't handle it just now.
            CONSOLE("%u: WARNING queue is full - discard data\n", pState->ucSerialPort);

            // Restore previous level of protection.
            SYS_ARCH_UNPROTECT(lev);

            // Free up the pbuf.  Note that we don't acknowledge receipt of
            // the data since we want it to be retransmitted later.
            pbuf_free(p);
        }
        else
        {
            // Place the pbuf in the circular queue.
            pState->pBufQ[pState->iBufQWrite] = p;

            // Increment the queue write index.
            pState->iBufQWrite = iNextWrite;

            // Restore previous level of protection.
            SYS_ARCH_UNPROTECT(lev);
        }
    }

    // If a null packet is passed in, close the connection.
    else if((err == ERR_OK) && (p == NULL))
    {
        CONSOLE("%u: received NULL packet - close connection\n", pState->ucSerialPort);

        // Clear out all of the TCP callbacks.
        tcp_arg(pcb, NULL);
        tcp_sent(pcb, NULL);
        tcp_recv(pcb, NULL);
        tcp_err(pcb, NULL);
        tcp_poll(pcb, NULL, 1);

        // Close the TCP connection.
        err = tcp_close(pcb);
        if (err != ERR_OK)
        {
           WARNING("%u: TelnetReceive.tcp_close failed, error=%d\n", pState->ucSerialPort, err);
           ErrorTCPOperation(pState->ucSerialPort, err, TCP_CLOSE_RECEIVE);
        }

        // Clear out any pbufs associated with this session.
        TelnetFreePbufs(pState);

        // Clear out the telnet session PCB.
        pState->pConnectPCB = NULL;

        StartConnection(pState->ucSerialPort);
    }

    CustomerSettings1_TelnetReceive(pState->ucSerialPort);

    return(ERR_OK);
}
コード例 #9
0
static err_t accept_tcp(void *arg, struct tcp_pcb *pcb, err_t err) {
	int		s, i, ns;
	sockfd_t	* fd, * nsd;
	err_t		rv = ERR_OK;

	// printf("kti: accept_tcp for %d called (err %d)\n", (int)arg, err);

	// Dunno what to do here if not...
	assert( err == ERR_OK );

	// Get the socket struct and lock
	s = (int)arg;
	if (sock_verify(s) < 0)
		return ERR_CONN;
	fd = fds + s;

	// Get access.
	mutex_lock(fd->mutex);

	// Do we have enough space?
	if (fd->conncnt >= fd->connmax) {
		rv = ERR_MEM;
		goto out;
	}

	// Add the connection
	for (i=0; i<fd->connmax; i++)
		if (fd->conns[i] < 0)
			break;
	if (i >= fd->connmax) {
		assert( 0 );
		rv = ERR_MEM;
		goto out;
	}

	// Create a new socket FD for the connection.
	ns = sock_open();
	if (ns < 0) {
		rv = ERR_MEM;
		goto out;
	}

	// Assign stuff. We've already got our sync objects, we just
	// need to get things into it. To make sure nothing weird happens
	// here, we'll lock first.
	nsd = fds + ns;
	mutex_lock(nsd->mutex);

	nsd->tcppcb = pcb;

	// Init our counters
	nsd->recv = 0;
	nsd->send = tcp_sndbuf(nsd->tcppcb);

	// Setup callbacks
	tcp_arg(nsd->tcppcb, (void *)ns);
	tcp_recv(nsd->tcppcb, recv_tcp);
	tcp_sent(nsd->tcppcb, sent_tcp);
	tcp_poll(nsd->tcppcb, poll_tcp, 4);	// 4 == 4 TCP timer intervals
	tcp_err(nsd->tcppcb, err_tcp);

	// Copy over the peer address
	nsd->name.sin_len = sizeof(struct sockaddr_in);
	nsd->name.sin_family = AF_INET;
	nsd->name.sin_port = htons(nsd->tcppcb->remote_port);
	nsd->name.sin_addr.s_addr = nsd->tcppcb->remote_ip.addr;

	mutex_unlock(nsd->mutex);


	fd->conns[i] = ns;
	fd->conncnt++;

	// Signal any thread waiting on accept()
	cond_signal(fd->connect);

out:
	mutex_unlock(fd->mutex);
	if (rv == ERR_OK)
		genwait_wake_all(&select_wait);
	return rv;
}
コード例 #10
0
ファイル: ftpd.c プロジェクト: skyformat99/lwip-ftpd
static void cmd_pasv(const char *arg, struct tcp_pcb *pcb, struct ftpd_msgstate *fsm)
{
	static u16_t port = 4096;
	static u16_t start_port = 4096;
	struct tcp_pcb *temppcb;

	/* Allocate memory for the structure that holds the state of the
	   connection. */
	fsm->datafs = malloc(sizeof(struct ftpd_datastate));

	if (fsm->datafs == NULL) {
		send_msg(pcb, fsm, msg451);
		return;
	}
	memset(fsm->datafs, 0, sizeof(struct ftpd_datastate));

	fsm->datapcb = tcp_new();
	if (!fsm->datapcb) {
		free(fsm->datafs);
		send_msg(pcb, fsm, msg451);
		return;
	}

	sfifo_init(&fsm->datafs->fifo, 2000);

	start_port = port;

	while (1) {
		err_t err;

		if(++port > 0x7fff)
			port = 4096;

		fsm->dataport = port;
		err = tcp_bind(fsm->datapcb, (ip_addr_t*)&pcb->local_ip, fsm->dataport);
		if (err == ERR_OK)
			break;
		if (start_port == port)
			err = ERR_CLSD;
		if (err == ERR_USE) {
			continue;
		} else {
			ftpd_dataclose(fsm->datapcb, fsm->datafs);
			fsm->datapcb = NULL;
			fsm->datafs = NULL;
			return;
		}
	}

	fsm->datafs->msgfs = fsm;

	temppcb = tcp_listen(fsm->datapcb);
	if (!temppcb) {
		ftpd_dataclose(fsm->datapcb, fsm->datafs);
		fsm->datapcb = NULL;
		fsm->datafs = NULL;
		return;
	}
	fsm->datapcb = temppcb;

	fsm->passive = 1;
	fsm->datafs->connected = 0;
	fsm->datafs->msgpcb = pcb;

	/* Tell TCP that this is the structure we wish to be passed for our
	   callbacks. */
	tcp_arg(fsm->datapcb, fsm->datafs);

	tcp_accept(fsm->datapcb, ftpd_dataaccept);
	send_msg(pcb, fsm, msg227, ip4_addr1(ip_2_ip4(&pcb->local_ip)), ip4_addr2(ip_2_ip4(&pcb->local_ip)), ip4_addr3(ip_2_ip4(&pcb->local_ip)), ip4_addr4(ip_2_ip4(&pcb->local_ip)), (fsm->dataport >> 8) & 0xff, (fsm->dataport) & 0xff);
}
コード例 #11
0
ファイル: ol_tcp.c プロジェクト: MCRedJay/ling
static term_t ol_tcp_control(outlet_t *ol,
		uint32_t op, uint8_t *data, int dlen, term_t reply_to, heap_t *hp)
{
	char rbuf[256];
	char *reply = rbuf;
	int sz;

	assert(ol != 0);
	assert(ol->tcp != 0 || op == INET_REQ_OPEN || op == INET_REQ_SUBSCRIBE);

	switch (op)
	{
	case INET_REQ_OPEN:
	{
		if (dlen != 2 || data[1] != INET_TYPE_STREAM)
			goto error;
		uint8_t family = data[0];
		if (family != INET_AF_INET && family != INET_AF_INET6)
			goto error;
		assert(ol->tcp == 0);

#if LWIP_IPV6
		ol->tcp = (family == INET_AF_INET6)
			?tcp_new_ip6()
			:tcp_new();
#else
		if (family != INET_AF_INET)
			goto error;
		ol->tcp = tcp_new();
#endif
		assert(ol->tcp != 0);

		// see comment in ol_tcp_animate()
		tcp_setprio(ol->tcp, TCP_PRIO_MAX +1);

		tcp_arg(ol->tcp, ol);	// callback arg
		tcp_recv(ol->tcp, recv_cb);
		tcp_sent(ol->tcp, sent_cb);
		tcp_err(ol->tcp, error_cb);

		*reply++ = INET_REP_OK;
	}
	break;

	case INET_REQ_CONNECT:
	{
		int is_ipv6 = PCB_ISIPV6(ol->tcp);
		if ((is_ipv6 && dlen != 4 +2 +16) || (!is_ipv6 && dlen != 4 +2 +4))
			goto error;

		uint32_t timeout = GET_UINT_32(data);
		uint16_t remote_port = GET_UINT_16(data +4);
	
		err_t err;
		if (!is_ipv6)
		{
			ip_addr_t where_to;
			where_to.addr = ntohl(GET_UINT_32(data +4 +2));
			err = tcp_connect(ol->tcp, &where_to, remote_port, connected_cb);
		}
		else
		{
#if LWIP_IPV6
			ip6_addr_t where_to;
			where_to.addr[0] = ntohl(GET_UINT_32(data +4 +2));
			where_to.addr[1] = ntohl(GET_UINT_32(data +4 +2 +4));
			where_to.addr[2] = ntohl(GET_UINT_32(data +4 +2 +8));
			where_to.addr[3] = ntohl(GET_UINT_32(data +4 +2 +12));
			err = tcp_connect_ip6(ol->tcp, &where_to, remote_port, connected_cb);
#else
			goto error;
#endif
		}

		// Does it make connections faster?
		tcp_output(ol->tcp);

		if (err == ERR_OK)
		{
			cr_defer_reply(ol, reply_to, timeout);

			*reply++ = INET_REP_OK;
			uint16_t ref = ASYNC_REF;	// Why this is needed? A constant will do.
			PUT_UINT_16(reply, ref);
			reply += 2;
		}
		else
		{
			//
			//TODO: ERR_RTE possible too (IPv6)
			//
			assert(err == ERR_MEM);
			REPLY_INET_ERROR("enomem");
		}
	}
	break;

	case INET_REQ_PEER:
	if (ol->tcp->state == CLOSED)
		REPLY_INET_ERROR("enotconn");
	else
	{
		*reply++ = INET_REP_OK;
		*reply++ = INET_AF_INET;
		uint16_t peer_port = ol->tcp->remote_port;
		PUT_UINT_16(reply, peer_port);
		reply += 2;
		if (PCB_ISIPV6(ol->tcp))
		{
			ip_addr_set_hton((ip_addr_t *)reply, (ip_addr_t *)&ol->tcp->remote_ip);
			reply += 4;
		}
		else
		{
#if LWIP_IPV6
			ip6_addr_set_hton((ip6_addr_t *)reply, (ip6_addr_t *)&ol->tcp->remote_ip);
			reply += 16;
#else
			goto error;
#endif
		}
	}
	break;

	case INET_REQ_NAME:
	if (ol->tcp->state == CLOSED)
		REPLY_INET_ERROR("enotconn");
	else
	{
		*reply++ = INET_REP_OK;
		int is_ipv6 = PCB_ISIPV6(ol->tcp);
		*reply++ = (is_ipv6) ?INET_AF_INET6 :INET_AF_INET;
		uint16_t name_port = ol->tcp->local_port;
		PUT_UINT_16(reply, name_port);
		reply += 2;
		if (PCB_ISIPV6(ol->tcp))
		{
			ip_addr_set_hton((ip_addr_t *)reply, (ip_addr_t *)&ol->tcp->local_ip);
			reply += 4;
		}
		else
		{
#if LWIP_IPV6
			ip6_addr_set_hton((ip6_addr_t *)reply, (ip6_addr_t *)&ol->tcp->local_ip);
			reply += 16;
#else
			goto error;
#endif
		}
	}
	break;

	case INET_REQ_BIND:
	{
		int is_ipv6 = PCB_ISIPV6(ol->tcp);
		if ((is_ipv6 && dlen != 2 +16) || (!is_ipv6 && dlen != 2 +4))
			goto error;
		uint16_t port = GET_UINT_16(data);
		if (!is_ipv6)
		{
			ip_addr_t addr;
			addr.addr = ntohl(GET_UINT_32(data +2));
			tcp_bind(ol->tcp, &addr, port); // always succeeds
		}
		else
		{
#if LWIP_IPV6
			ip6_addr_t addr;
			addr.addr[0] = ntohl(GET_UINT_32(data +2));
			addr.addr[1] = ntohl(GET_UINT_32(data +2 +4));
			addr.addr[2] = ntohl(GET_UINT_32(data +2 +8));
			addr.addr[3] = ntohl(GET_UINT_32(data +2 +12));
			tcp_bind_ip6(ol->tcp, &addr, port); // always succeeds
#else
			goto error;
#endif
		}

		uint16_t local_port = ol->tcp->local_port;
		*reply++ = INET_REP_OK;
		PUT_UINT_16(reply, local_port);
		reply += 2;
	}
	break;

	case INET_REQ_LISTEN:
	{
		assert(ol->recv_buf_node == 0);	// or use destroy_private()
		int backlog = GET_UINT_16(data);
		ol_tcp_acc_promote(ol, ol->tcp, backlog);
		*reply++ = INET_REP_OK;
	}
	break;

	case INET_REQ_SETOPTS:
	if (ol_tcp_set_opts(ol, data, dlen) < 0)
		goto error;

	*reply++ = INET_REP_OK;
	break;

	case INET_REQ_GETOPTS:
	sz = ol_tcp_get_opts(ol, data, dlen, rbuf+1, sizeof(rbuf) -1);
	if (sz < 0)
		goto error;

	*reply++ = INET_REP_OK;
	reply += sz;
	break;

	case INET_REQ_GETSTAT:
	//
	// lwIP can provide some of the statistics but not all
	//
	REPLY_INET_ERROR("enotsup");
	break;

	case INET_REQ_SUBSCRIBE:
	if (dlen != 1 && data[0] != INET_SUBS_EMPTY_OUT_Q)
		goto error;
	if (ol->empty_queue_in_progress)
		goto error;		//TODO: allow multiple subscriptions

	int qlen = tcp_sndqueuelen(ol->tcp);
	if (qlen > 0)
	{
		ol->empty_queue_in_progress = 1;
		ol->empty_queue_reply_to = reply_to;
	}

	*reply++ = INET_REP_OK;
	*reply++ = INET_SUBS_EMPTY_OUT_Q;
	PUT_UINT_32(reply, qlen);
	reply += 4;
	break;

	case TCP_REQ_RECV:
	if (dlen != 4 +4)
		goto error;

	uint32_t msecs = GET_UINT_32(data);
	uint32_t recv_num = GET_UINT_32(data +4);

	if (ol->active != INET_PASSIVE)
		goto error;
	if (ol->packet == TCP_PB_RAW && recv_num > ol->recv_bufsize)
		goto error;
	
	if (ol->peer_close_detected)
		inet_async_error(ol->oid, reply_to, ASYNC_REF, A_CLOSED);
	else
	{
		cr_defer_reply(ol, reply_to, msecs);

		if (ol->packet == TCP_PB_RAW)
			ol->recv_expected_size = recv_num;

		// Enough data may have already been buffered
		proc_t *cont_proc = scheduler_lookup(reply_to);
		assert(cont_proc != 0);
		if (recv_bake_packets(ol, cont_proc) < 0)
			goto error;
	}

	*reply++ = INET_REP_OK;
	uint16_t my_ref = ASYNC_REF;
	PUT_UINT_16(reply, my_ref);
	reply += 2;
	break;

	case TCP_REQ_SHUTDOWN:
	if (dlen != 1)
		goto error;

	uint8_t what = data[0];
	// 0 - read
	// 1 - write
	// 2 - read_write
	
	int shut_rx = (what == 0) || (what == 2);
	int shut_tx = (what == 1) || (what == 2);

	if (ol->tcp->state == LISTEN)
		REPLY_INET_ERROR("enotconn");
	else
	{
		tcp_shutdown(ol->tcp, shut_rx, shut_tx);
		// TODO: return code ignored

		*reply++ = INET_REP_OK;
	}
	break;

	default:
error:
	REPLY_INET_ERROR("einval");
	}

	int rlen = reply -rbuf;
	assert(rlen >= 1 && rlen <= sizeof(rbuf));
	term_t result = heap_str_N(hp, rbuf, rlen);
	if (result == noval)
		return A_NO_MEMORY;

	return result;
}
コード例 #12
0
ファイル: tcp_server.c プロジェクト: Karamax/arrakis
static void tcp_server_bm_close(struct tcp_pcb *tpcb)
{
    tcp_arg(tpcb, NULL);
    tcp_close(tpcb);
}
コード例 #13
0
ファイル: smtp.c プロジェクト: AleksKolkov/lrndis
/** The actual mail-sending function, called by smtp_send_mail and
 * smtp_send_mail_static after setting up the struct smtp_session.
 */
static err_t
smtp_send_mail_alloced(struct smtp_session *s)
{
  err_t err;
  struct tcp_pcb* pcb;
  ip_addr_t addr;

  LWIP_ASSERT("no smtp_session supplied", s != NULL);

#if SMTP_CHECK_DATA
  /* check that body conforms to RFC:
   * - convert all single-CR or -LF in body to CRLF
   * - only 7-bit ASCII is allowed
   */
  if (smtp_verify(s->to, s->to_len, 0) != ERR_OK) {
    return ERR_ARG;
  }
  if (smtp_verify(s->from, s->from_len, 0) != ERR_OK) {
    return ERR_ARG;
  }
  if (smtp_verify(s->subject, s->subject_len, 0) != ERR_OK) {
    return ERR_ARG;
  }
  if (smtp_verify(s->body, s->body_len, 0) != ERR_OK) {
    return ERR_ARG;
  }
#endif /* SMTP_CHECK_DATA */

  pcb = tcp_new();
  if (pcb == NULL) {
    err = ERR_MEM;
    goto leave;
  }

#if SMTP_COPY_AUTHDATA
  /* copy auth data, ensuring the first byte is always zero */
  memcpy(s->auth_plain + 1, smtp_auth_plain + 1, smtp_auth_plain_len - 1);
  s->auth_plain_len = smtp_auth_plain_len;
  /* default username and pass is empty string */
  s->username = s->auth_plain;
  s->pass = s->auth_plain;
  if (smtp_username != NULL) {
    s->username += smtp_username - smtp_auth_plain;
  }
  if (smtp_pass != NULL) {
    s->pass += smtp_pass - smtp_auth_plain;
  }
#endif /* SMTP_COPY_AUTHDATA */

  s->state = SMTP_NULL;
  s->timer = SMTP_TIMEOUT;

  tcp_arg(pcb, s);
  tcp_recv(pcb, smtp_tcp_recv);
  tcp_err(pcb, smtp_tcp_err);
  tcp_poll(pcb, smtp_tcp_poll, SMTP_POLL_INTERVAL);
  tcp_sent(pcb, smtp_tcp_sent);

#if LWIP_DNS
  err = dns_gethostbyname(smtp_server, &addr, smtp_dns_found, pcb);
#else /* LWIP_DNS */
  addr.addr = ipaddr_addr(smtp_server);
  err = addr.addr == IPADDR_NONE ? ERR_ARG : ERR_OK;
#endif /* LWIP_DNS */
  if (err == ERR_OK) {
    err = tcp_connect(pcb, &addr, smtp_server_port, smtp_tcp_connected);
    if (err != ERR_OK) {
      LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("tcp_connect failed: %d\n", (int)err));
      goto deallocate_and_leave;
    }
  } else if (err != ERR_INPROGRESS) {
    LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("dns_gethostbyname failed: %d\n", (int)err));
    goto deallocate_and_leave;
  }
  return ERR_OK;

deallocate_and_leave:
  if (pcb != NULL) {
    tcp_arg(pcb, NULL);
    tcp_close(pcb);
  }
leave:
  mem_free(s);
  /* no need to call the callback here since we return != ERR_OK */
  return err;
}
コード例 #14
0
ファイル: smtp.c プロジェクト: AleksKolkov/lrndis
/** State machine-like implementation of an SMTP client.
 */
static void
smtp_process(void *arg, struct tcp_pcb *pcb, struct pbuf *p)
{
  struct smtp_session* s = arg;
  u16_t response_code = 0;
  u16_t tx_buf_len = 0;
  enum smtp_session_state next_state;

  if (arg == NULL) {
    /* already closed SMTP connection */
    if (p != NULL) {
      LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("Received %d bytes after closing: %s\n",
        p->tot_len, smtp_pbuf_str(p)));
      pbuf_free(p);
    }
    return;
  }

  next_state = s->state;

  if (p != NULL) {
    /* received data */
    if (s->p == NULL) {
      s->p = p;
    } else {
      pbuf_cat(s->p, p);
    }
  } else {
    /* idle timer, close connection if timed out */
    if (s->timer == 0) {
      LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_process: connection timed out, closing\n"));
      smtp_close(s, pcb, SMTP_RESULT_ERR_TIMEOUT, 0, ERR_TIMEOUT);
      return;
    }
    if (s->state == SMTP_BODY) {
      smtp_send_body(s, pcb);
      return;
    }
  }
  response_code = smtp_is_response(s);
  if (response_code) {
    LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: received response code: %d\n", response_code));
    if (smtp_is_response_finished(s) != ERR_OK) {
      LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process: partly received response code: %d\n", response_code));
      /* wait for next packet to complete the respone */
      return;
    }
  } else {
    if (s->p != NULL) {
      LWIP_DEBUGF(SMTP_DEBUG_WARN, ("smtp_process: unknown data received (%s)\n",
        smtp_pbuf_str(s->p)));
      pbuf_free(s->p);
      s->p = NULL;
    }
    return;
  }

  switch(s->state)
  {
  case(SMTP_NULL):
    /* wait for 220 */
    if (response_code == 220) {
      /* then send EHLO */
      next_state = smtp_prepare_helo(s, &tx_buf_len, pcb);
    }
    break;
  case(SMTP_HELO):
    /* wait for 250 */
    if (response_code == 250) {
#if SMTP_SUPPORT_AUTH_AUTH || SMTP_SUPPORT_AUTH_LOGIN
      /* then send AUTH or MAIL */
      next_state = smtp_prepare_auth_or_mail(s, &tx_buf_len);
    }
    break;
  case(SMTP_AUTH_LOGIN):
  case(SMTP_AUTH_PLAIN):
    /* wait for 235 */
    if (response_code == 235) {
#endif /* SMTP_SUPPORT_AUTH_AUTH || SMTP_SUPPORT_AUTH_LOGIN */
      /* send MAIL */
      next_state = smtp_prepare_mail(s, &tx_buf_len);
    }
    break;
#if SMTP_SUPPORT_AUTH_LOGIN
  case(SMTP_AUTH_LOGIN_UNAME):
    /* wait for 334 Username */
    if (response_code == 334) {
      if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_UNAME) != 0xFFFF) {
        /* send username */
        next_state = smtp_prepare_auth_login_uname(s, &tx_buf_len);
      }
    }
    break;
  case(SMTP_AUTH_LOGIN_PASS):
    /* wait for 334 Password */
    if (response_code == 334) {
      if (pbuf_strstr(s->p, SMTP_RESP_LOGIN_PASS) != 0xFFFF) {
        /* send username */
        next_state = smtp_prepare_auth_login_pass(s, &tx_buf_len);
      }
    }
    break;
#endif /* SMTP_SUPPORT_AUTH_LOGIN */
  case(SMTP_MAIL):
    /* wait for 250 */
    if (response_code == 250) {
      /* send RCPT */
      next_state = smtp_prepare_rcpt(s, &tx_buf_len);
    }
    break;
  case(SMTP_RCPT):
    /* wait for 250 */
    if (response_code == 250) {
      /* send DATA */
      SMEMCPY(s->tx_buf, SMTP_CMD_DATA, SMTP_CMD_DATA_LEN);
      tx_buf_len = SMTP_CMD_DATA_LEN;
      next_state = SMTP_DATA;
    }
    break;
  case(SMTP_DATA):
    /* wait for 354 */
    if (response_code == 354) {
      /* send email header */
      next_state = smtp_prepare_header(s, &tx_buf_len);
    }
    break;
  case(SMTP_BODY):
    /* nothing to be done here, handled somewhere else */
    break;
  case(SMTP_QUIT):
    /* wait for 250 */
    if (response_code == 250) {
      /* send QUIT */
      next_state = smtp_prepare_quit(s, &tx_buf_len);
    }
    break;
  case(SMTP_CLOSED):
    /* nothing to do, wait for connection closed from server */
    return;
  default:
    LWIP_DEBUGF(SMTP_DEBUG_SERIOUS, ("Invalid state: %d/%s\n", (int)s->state,
      smtp_state_str[s->state]));
    break;
  }
  if (s->state == next_state) {
    LWIP_DEBUGF(SMTP_DEBUG_WARN_STATE, ("smtp_process[%s]: unexpected response_code, closing: %d (%s)\n",
      smtp_state_str[s->state], response_code, smtp_pbuf_str(s->p)));
    /* close connection */
    smtp_close(s, pcb, SMTP_RESULT_ERR_SVR_RESP, response_code, ERR_OK);
    return;
  }
  if (tx_buf_len > 0) {
    SMTP_TX_BUF_MAX(tx_buf_len);
    if (tcp_write(pcb, s->tx_buf, tx_buf_len, TCP_WRITE_FLAG_COPY) == ERR_OK) {
      LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process[%s]: received command %d (%s)\n",
        smtp_state_str[s->state], response_code, smtp_pbuf_str(s->p)));
      LWIP_DEBUGF(SMTP_DEBUG_TRACE, ("smtp_process[%s]: sent %"U16_F" bytes: \"%s\"\n",
        smtp_state_str[s->state], tx_buf_len, s->tx_buf));
      s->timer = SMTP_TIMEOUT;
      pbuf_free(s->p);
      s->p = NULL;
      LWIP_DEBUGF(SMTP_DEBUG_STATE, ("smtp_process: changing state from %s to %s\n",
        smtp_state_str[s->state], smtp_state_str[next_state]));
      s->state = next_state;
      if (next_state == SMTP_BODY) {
        /* try to stream-send body data right now */
        smtp_send_body(s, pcb);
      } else if (next_state == SMTP_CLOSED) {
        /* sent out all data, delete structure */
        tcp_arg(pcb, NULL);
        smtp_free(s, SMTP_RESULT_OK, 0, ERR_OK);
      }
    }
  }
}
コード例 #15
0
ファイル: api_msg.c プロジェクト: cya410/libraries
/**
 * Set a TCP pcb contained in a netconn into listen mode
 * Called from netconn_listen.
 *
 * @param msg the api_msg_msg pointing to the connection
 */
void
lwip_netconn_do_listen(struct api_msg_msg *msg)
{
  if (ERR_IS_FATAL_LISTENCONNECT(msg->conn->last_err)) {
    msg->err = msg->conn->last_err;
  } else {
    msg->err = ERR_CONN;
    if (msg->conn->pcb.tcp != NULL) {
      if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_TCP) {
        if (msg->conn->state == NETCONN_NONE) {
          struct tcp_pcb* lpcb;
          if (msg->conn->pcb.tcp->state != CLOSED) {
            /* connection is not closed, cannot listen */
            msg->err = ERR_VAL;
          } else {
#if LWIP_IPV6
            if ((msg->conn->flags & NETCONN_FLAG_IPV6_V6ONLY) == 0) {
#if TCP_LISTEN_BACKLOG
              lpcb = tcp_listen_dual_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
#else  /* TCP_LISTEN_BACKLOG */
              lpcb = tcp_listen_dual(msg->conn->pcb.tcp);
#endif /* TCP_LISTEN_BACKLOG */
            } else
#endif /* LWIP_IPV6 */
            {
#if TCP_LISTEN_BACKLOG
              lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
#else  /* TCP_LISTEN_BACKLOG */
              lpcb = tcp_listen(msg->conn->pcb.tcp);
#endif /* TCP_LISTEN_BACKLOG */
            }
            if (lpcb == NULL) {
              /* in this case, the old pcb is still allocated */
              msg->err = ERR_MEM;
            } else {
              /* delete the recvmbox and allocate the acceptmbox */
              if (sys_mbox_valid(&msg->conn->recvmbox)) {
                /** @todo: should we drain the recvmbox here? */
                sys_mbox_free(&msg->conn->recvmbox);
                sys_mbox_set_invalid(&msg->conn->recvmbox);
              }
              msg->err = ERR_OK;
              if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
                msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
              }
              if (msg->err == ERR_OK) {
                msg->conn->state = NETCONN_LISTEN;
                msg->conn->pcb.tcp = lpcb;
                tcp_arg(msg->conn->pcb.tcp, msg->conn);
                tcp_accept(msg->conn->pcb.tcp, accept_function);
              } else {
                /* since the old pcb is already deallocated, free lpcb now */
                tcp_close(lpcb);
                msg->conn->pcb.tcp = NULL;
              }
            }
          }
        }
      } else {
        msg->err = ERR_ARG;
      }
    }
  }
  TCPIP_APIMSG_ACK(msg);
}
コード例 #16
0
int lwip_connect(int s, struct sockaddr *name, socklen_t namelen) {
	sockfd_t	* fd;
	struct ip_addr	ip;
	int		port, rv = 0;

	s = sock_for_fd(s);
	if (s < 0) {
		errno = EBADF;
		return -1;
	}
	fd = fds + s;

	// Make sure it's an internet address we understand.
	if (namelen != sizeof(struct sockaddr_in)) {
		errno = ENAMETOOLONG;
		return -1;
	}

	// Get access
	mutex_lock(fd->mutex);

	// Copy it over
	memcpy(&fd->name, name, namelen);

	// Convert this to an lwIP-happy format
	ip.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;
	port = ((struct sockaddr_in *)name)->sin_port;

	// Are we TCP or UDP?
	switch (fd->type) {
	case SOCK_STREAM:
		// This might have gotten made already, bind is valid on
		// outgoing sockets too.
		if (!fd->tcppcb)
			fd->tcppcb = tcp_new();
		tcp_arg(fd->tcppcb, (void *)s);
		tcp_recv(fd->tcppcb, recv_tcp);
		tcp_sent(fd->tcppcb, sent_tcp);
		tcp_poll(fd->tcppcb, poll_tcp, 4);	// 4 == 4 TCP timer intervals
		tcp_err(fd->tcppcb, err_tcp);
		if (tcp_connect(fd->tcppcb, &ip, ntohs(port), connect_tcp) != ERR_OK) {
			if (tcp_close(fd->tcppcb) != ERR_OK)
				tcp_abort(fd->tcppcb);
			fd->tcppcb = NULL;
			errno = EINVAL;
			rv = -1; goto out;
		}
		break;
	case SOCK_DGRAM:
		// This might have gotten made already, bind is valid on
		// outgoing sockets too.
		if (!fd->udppcb)
			fd->udppcb = udp_new();
		udp_recv(fd->udppcb, recv_udp, (void *)s);
		udp_connect(fd->udppcb, &ip, ntohs(port));
		break;
	default:
		assert( 0 );
		errno = EINVAL;
		rv = -1; goto out;
	}

	// If we are doing a TCP connect, we need to wait for the results
	// of the operation.
	if (fd->type == SOCK_STREAM) {
		// Wait for the result
		fd->connerr = 10;
		while (fd->connerr > 0) {
			cond_wait(fd->connect, fd->mutex);
		}

		// Convert error codes
		switch (fd->connerr) {
		case ERR_OK: break;
		
		case ERR_MEM:
		case ERR_BUF:
		case ERR_VAL:
		case ERR_ARG:
		case ERR_IF:
			errno = EINVAL;
			rv = -1;
			goto out;

		case ERR_ABRT:
		case ERR_RST:
		case ERR_CLSD:
		case ERR_CONN:
			errno = ECONNREFUSED;
			rv = -1;
			goto out;

		case ERR_RTE:
			errno = ENETUNREACH;
			rv = -1;
			goto out;

		case ERR_USE:
			errno = EADDRINUSE;
			rv = -1;
			goto out;
		}

		if (fd->connerr == ERR_OK) {
			// Init our counters
			fd->recv = 0;
			fd->send = tcp_sndbuf(fd->tcppcb);
		}
	}

out:
	mutex_unlock(fd->mutex);
	return rv;
}
コード例 #17
0
STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
    lwip_socket_obj_t *socket = self_in;

    if (socket->pcb.tcp == NULL) {
        mp_raise_OSError(MP_EBADF);
    }
    if (socket->type != MOD_NETWORK_SOCK_STREAM) {
        mp_raise_OSError(MP_EOPNOTSUPP);
    }
    // I need to do this because "tcp_accepted", later, is a macro.
    struct tcp_pcb *listener = socket->pcb.tcp;
    if (listener->state != LISTEN) {
        mp_raise_OSError(MP_EINVAL);
    }

    // accept incoming connection
    if (socket->incoming.connection == NULL) {
        if (socket->timeout == 0) {
            mp_raise_OSError(MP_EAGAIN);
        } else if (socket->timeout != -1) {
            for (mp_uint_t retries = socket->timeout / 100; retries--;) {
                mp_hal_delay_ms(100);
                if (socket->incoming.connection != NULL) break;
            }
            if (socket->incoming.connection == NULL) {
                mp_raise_OSError(MP_ETIMEDOUT);
            }
        } else {
            while (socket->incoming.connection == NULL) {
                poll_sockets();
            }
        }
    }

    // create new socket object
    lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t);
    socket2->base.type = (mp_obj_t)&lwip_socket_type;

    // We get a new pcb handle...
    socket2->pcb.tcp = socket->incoming.connection;
    socket->incoming.connection = NULL;

    // ...and set up the new socket for it.
    socket2->domain = MOD_NETWORK_AF_INET;
    socket2->type = MOD_NETWORK_SOCK_STREAM;
    socket2->incoming.pbuf = NULL;
    socket2->timeout = socket->timeout;
    socket2->state = STATE_CONNECTED;
    socket2->recv_offset = 0;
    socket2->callback = MP_OBJ_NULL;
    tcp_arg(socket2->pcb.tcp, (void*)socket2);
    tcp_err(socket2->pcb.tcp, _lwip_tcp_error);
    tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv);

    tcp_accepted(listener);

    // make the return value
    uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
    memcpy(ip, &(socket2->pcb.tcp->remote_ip), sizeof(ip));
    mp_uint_t port = (mp_uint_t)socket2->pcb.tcp->remote_port;
    mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);
    client->items[0] = socket2;
    client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);

    return client;
}
コード例 #18
0
ファイル: net.c プロジェクト: Dxploto/nodemcu-firmware
// Lua: server:listen(port, addr, function(c)), socket:listen(port, addr)
int net_listen( lua_State *L ) {
  lnet_userdata *ud = net_get_udata(L);
  if (!ud || ud->type == TYPE_TCP_CLIENT)
    return luaL_error(L, "invalid user data");
  if (ud->pcb)
    return luaL_error(L, "already listening");
  int stack = 2;
  uint16_t port = 0;
  const char *domain = "0.0.0.0";
  if (lua_isnumber(L, stack))
    port = lua_tointeger(L, stack++);
  if (lua_isstring(L, stack)) {
    size_t dl = 0;
    domain = luaL_checklstring(L, stack++, &dl);
  }
  ip_addr_t addr;
  if (!ipaddr_aton(domain, &addr))
    return luaL_error(L, "invalid IP address");
  if (ud->type == TYPE_TCP_SERVER) {
    if (lua_isfunction(L, stack) || lua_islightfunction(L, stack)) {
      lua_pushvalue(L, stack++);
      luaL_unref(L, LUA_REGISTRYINDEX, ud->server.cb_accept_ref);
      ud->server.cb_accept_ref = luaL_ref(L, LUA_REGISTRYINDEX);
    } else {
      return luaL_error(L, "need callback");
    }
  }
  err_t err = ERR_OK;
  switch (ud->type) {
    case TYPE_TCP_SERVER:
      ud->tcp_pcb = tcp_new();
      if (!ud->tcp_pcb)
        return luaL_error(L, "cannot allocate PCB");
      ud->tcp_pcb->so_options |= SOF_REUSEADDR;
      err = tcp_bind(ud->tcp_pcb, &addr, port);
      if (err == ERR_OK) {
        tcp_arg(ud->tcp_pcb, ud);
        struct tcp_pcb *pcb = tcp_listen(ud->tcp_pcb);
        if (!pcb) {
          err = ERR_MEM;
        } else {
          ud->tcp_pcb = pcb;
          tcp_accept(ud->tcp_pcb, net_accept_cb);
        }
      }
      break;
    case TYPE_UDP_SOCKET:
      ud->udp_pcb = udp_new();
      if (!ud->udp_pcb)
        return luaL_error(L, "cannot allocate PCB");
      udp_recv(ud->udp_pcb, net_udp_recv_cb, ud);
      err = udp_bind(ud->udp_pcb, &addr, port);
      break;
  }
  if (err != ERR_OK) {
    switch (ud->type) {
      case TYPE_TCP_SERVER:
        tcp_close(ud->tcp_pcb);
        ud->tcp_pcb = NULL;
        break;
      case TYPE_UDP_SOCKET:
        udp_remove(ud->udp_pcb);
        ud->udp_pcb = NULL;
        break;
    }
    return lwip_lua_checkerr(L, err);
  }
  if (ud->self_ref == LUA_NOREF) {
    lua_pushvalue(L, 1);
    ud->self_ref = luaL_ref(L, LUA_REGISTRYINDEX);
  }
  return 0;
}
コード例 #19
0
ファイル: api_msg.c プロジェクト: malooei/yeejoin-workspace
/**
 * Receive callback function for UDP netconns.
 * Posts the packet to conn->recvmbox or deletes it on memory error.
 *
 * @see udp.h (struct udp_pcb.recv) for parameters
 */
static void
recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
		 ip_addr_t *addr, u16_t port)
{
	struct netbuf *buf;
	struct netconn *conn;
	u16_t len;
#if LWIP_SO_RCVBUF
	int recv_avail;
#endif /* LWIP_SO_RCVBUF */

	LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
	LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
	LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
	conn = (struct netconn *)arg;
	LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);

#if LWIP_SO_RCVBUF
	SYS_ARCH_GET(conn->recv_avail, recv_avail);
	if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||
		((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
#else  /* LWIP_SO_RCVBUF */
	if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {
#endif /* LWIP_SO_RCVBUF */
		pbuf_free(p);
		return;
	}

	buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
	if (buf == NULL) {
		pbuf_free(p);
		return;
	} else {
		buf->p = p;
		buf->ptr = p;
		ip_addr_set(&buf->addr, addr);
		buf->port = port;
#if LWIP_NETBUF_RECVINFO
		{
			const struct ip_hdr* iphdr = ip_current_header();
			/* get the UDP header - always in the first pbuf, ensured by udp_input */
			const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
#if LWIP_CHECKSUM_ON_COPY
			buf->flags = NETBUF_FLAG_DESTADDR;
#endif /* LWIP_CHECKSUM_ON_COPY */
			ip_addr_set(&buf->toaddr, ip_current_dest_addr());
			buf->toport_chksum = udphdr->dest;
		}
#endif /* LWIP_NETBUF_RECVINFO */
	}

	len = p->tot_len;
	if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
		netbuf_delete(buf);
		return;
	} else {
#if LWIP_SO_RCVBUF
		SYS_ARCH_INC(conn->recv_avail, len);
#endif /* LWIP_SO_RCVBUF */
		/* Register event with callback */
		API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
	}
}
#endif /* LWIP_UDP */

#if LWIP_TCP
/**
 * Receive callback function for TCP netconns.
 * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
 *
 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
 */
static err_t
recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
	struct netconn *conn;
	u16_t len;

	LWIP_UNUSED_ARG(pcb);
	LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
	LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
	conn = (struct netconn *)arg;
	LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);

	if (conn == NULL) {
		return ERR_VAL;
	}
	if (!sys_mbox_valid(&conn->recvmbox)) {
		/* recvmbox already deleted */
		if (p != NULL) {
			tcp_recved(pcb, p->tot_len);
			pbuf_free(p);
		}
		return ERR_OK;
	}
	/* Unlike for UDP or RAW pcbs, don't check for available space
	   using recv_avail since that could break the connection
	   (data is already ACKed) */

	/* don't overwrite fatal errors! */
	NETCONN_SET_SAFE_ERR(conn, err);

	if (p != NULL) {
		len = p->tot_len;
	} else {
		len = 0;
	}

	if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
		/* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
		return ERR_MEM;
	} else {
#if LWIP_SO_RCVBUF
		SYS_ARCH_INC(conn->recv_avail, len);
#endif /* LWIP_SO_RCVBUF */
		/* Register event with callback */
		API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
	}

	return ERR_OK;
}

/**
 * Poll callback function for TCP netconns.
 * Wakes up an application thread that waits for a connection to close
 * or data to be sent. The application thread then takes the
 * appropriate action to go on.
 *
 * Signals the conn->sem.
 * netconn_close waits for conn->sem if closing failed.
 *
 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
 */
static err_t
poll_tcp(void *arg, struct tcp_pcb *pcb)
{
	struct netconn *conn = (struct netconn *)arg;

	LWIP_UNUSED_ARG(pcb);
	LWIP_ASSERT("conn != NULL", (conn != NULL));

	if (conn->state == NETCONN_WRITE) {
		do_writemore(conn);
	} else if (conn->state == NETCONN_CLOSE) {
		do_close_internal(conn);
	}
	/* @todo: implement connect timeout here? */

	/* Did a nonblocking write fail before? Then check available write-space. */
	if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
		/* If the queued byte- or pbuf-count drops below the configured low-water limit,
		   let select mark this pcb as writable again. */
		if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
			(tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
			conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
			API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
		}
	}

	return ERR_OK;
}

/**
 * Sent callback function for TCP netconns.
 * Signals the conn->sem and calls API_EVENT.
 * netconn_write waits for conn->sem if send buffer is low.
 *
 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
 */
static err_t
sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
{
	struct netconn *conn = (struct netconn *)arg;

	LWIP_UNUSED_ARG(pcb);
	LWIP_ASSERT("conn != NULL", (conn != NULL));

	if (conn->state == NETCONN_WRITE) {
		do_writemore(conn);
	} else if (conn->state == NETCONN_CLOSE) {
		do_close_internal(conn);
	}

	if (conn) {
		/* If the queued byte- or pbuf-count drops below the configured low-water limit,
		   let select mark this pcb as writable again. */
		if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
			(tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
			conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
			API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
		}
	}

	return ERR_OK;
}

/**
 * Error callback function for TCP netconns.
 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
 * The application thread has then to decide what to do.
 *
 * @see tcp.h (struct tcp_pcb.err) for parameters
 */
static void
err_tcp(void *arg, err_t err)
{
	struct netconn *conn;
	enum netconn_state old_state;
	SYS_ARCH_DECL_PROTECT(lev);

	conn = (struct netconn *)arg;
	LWIP_ASSERT("conn != NULL", (conn != NULL));

	conn->pcb.tcp = NULL;

	/* no check since this is always fatal! */
	SYS_ARCH_PROTECT(lev);
	conn->last_err = err;
	SYS_ARCH_UNPROTECT(lev);

	/* reset conn->state now before waking up other threads */
	old_state = conn->state;
	conn->state = NETCONN_NONE;

	/* Notify the user layer about a connection error. Used to signal
	   select. */
	API_EVENT(conn, NETCONN_EVT_ERROR, 0);
	/* Try to release selects pending on 'read' or 'write', too.
	   They will get an error if they actually try to read or write. */
	API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
	API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);

	/* pass NULL-message to recvmbox to wake up pending recv */
	if (sys_mbox_valid(&conn->recvmbox)) {
		/* use trypost to prevent deadlock */
		sys_mbox_trypost(&conn->recvmbox, NULL);
	}
	/* pass NULL-message to acceptmbox to wake up pending accept */
	if (sys_mbox_valid(&conn->acceptmbox)) {
		/* use trypost to preven deadlock */
		sys_mbox_trypost(&conn->acceptmbox, NULL);
	}

	if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
		(old_state == NETCONN_CONNECT)) {
		/* calling do_writemore/do_close_internal is not necessary
		   since the pcb has already been deleted! */
		int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
		SET_NONBLOCKING_CONNECT(conn, 0);

		if (!was_nonblocking_connect) {
			/* set error return code */
			LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
			conn->current_msg->err = err;
			conn->current_msg = NULL;
			/* wake up the waiting task */
			sys_sem_signal(&conn->op_completed);
		}
	} else {
		LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
	}
}

/**
 * Setup a tcp_pcb with the correct callback function pointers
 * and their arguments.
 *
 * @param conn the TCP netconn to setup
 */
static void
setup_tcp(struct netconn *conn)
{
	struct tcp_pcb *pcb;

	pcb = conn->pcb.tcp;
	tcp_arg(pcb, conn);
	tcp_recv(pcb, recv_tcp);
	tcp_sent(pcb, sent_tcp);
	tcp_poll(pcb, poll_tcp, 4);
	tcp_err(pcb, err_tcp);
}

/**
 * Accept callback function for TCP netconns.
 * Allocates a new netconn and posts that to conn->acceptmbox.
 *
 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
 */
static err_t
accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
{
	struct netconn *newconn;
	struct netconn *conn = (struct netconn *)arg;

	LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));

	if (!sys_mbox_valid(&conn->acceptmbox)) {
		LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
		return ERR_VAL;
	}

	/* We have to set the callback here even though
	 * the new socket is unknown. conn->socket is marked as -1. */
	newconn = netconn_alloc(conn->type, conn->callback);
	if (newconn == NULL) {
		return ERR_MEM;
	}
	newconn->pcb.tcp = newpcb;
	setup_tcp(newconn);
	/* no protection: when creating the pcb, the netconn is not yet known
	   to the application thread */
	newconn->last_err = err;

	if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
		/* When returning != ERR_OK, the pcb is aborted in tcp_process(),
		   so do nothing here! */
		newconn->pcb.tcp = NULL;
		/* no need to drain since we know the recvmbox is empty. */
		sys_mbox_free(&newconn->recvmbox);
		sys_mbox_set_invalid(&newconn->recvmbox);
		netconn_free(newconn);
		return ERR_MEM;
	} else {
		/* Register event with callback */
		API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
	}

	return ERR_OK;
}
#endif /* LWIP_TCP */

/**
 * Create a new pcb of a specific type.
 * Called from do_newconn().
 *
 * @param msg the api_msg_msg describing the connection type
 * @return msg->conn->err, but the return value is currently ignored
 */
static void
pcb_new(struct api_msg_msg *msg)
{
	LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);

	/* Allocate a PCB for this connection */
	switch(NETCONNTYPE_GROUP(msg->conn->type)) {
#if LWIP_RAW
	case NETCONN_RAW:
		msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
		if(msg->conn->pcb.raw == NULL) {
			msg->err = ERR_MEM;
			break;
		}
		raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
		break;
#endif /* LWIP_RAW */
#if LWIP_UDP
	case NETCONN_UDP:
		msg->conn->pcb.udp = udp_new();
		if(msg->conn->pcb.udp == NULL) {
			msg->err = ERR_MEM;
			break;
		}
#if LWIP_UDPLITE
		if (msg->conn->type==NETCONN_UDPLITE) {
			udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
		}
#endif /* LWIP_UDPLITE */
		if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
			udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
		}
		udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
		break;
#endif /* LWIP_UDP */
#if LWIP_TCP
	case NETCONN_TCP:
		msg->conn->pcb.tcp = tcp_new();
		if(msg->conn->pcb.tcp == NULL) {
			msg->err = ERR_MEM;
			break;
		}
		setup_tcp(msg->conn);
		break;
#endif /* LWIP_TCP */
	default:
		/* Unsupported netconn type, e.g. protocol disabled */
		msg->err = ERR_VAL;
		break;
	}
}
コード例 #20
0
ファイル: espconn_tcp.c プロジェクト: FRANZEE/esp8266web
/******************************************************************************
 * FunctionName : espconn_tcp_accept
 * Description  : A new incoming connection has been accepted.
 * Parameters   : arg -- Additional argument to pass to the callback function
 *                pcb -- The connection pcb which is accepted
 *                err -- An unused error code, always ERR_OK currently
 * Returns      : acception result
*******************************************************************************/
static err_t ICACHE_FLASH_ATTR
espconn_tcp_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
    struct espconn *espconn = arg;
    espconn_msg *paccept = NULL;
    remot_info *pinfo = NULL;
    LWIP_UNUSED_ARG(err);

    if (!espconn || !espconn->proto.tcp) {
    	return ERR_ARG;
    }

    tcp_arg(pcb, paccept);
    tcp_err(pcb, esponn_server_err);
    /*Ensure the active connection is less than the count of active connections on the server*/
    espconn_get_connection_info(espconn, &pinfo , 0);
	espconn_printf("espconn_tcp_accept link_cnt: %d\n", espconn->link_cnt);
	if (espconn->link_cnt == espconn_tcp_get_max_con_allow(espconn))
		return ERR_ISCONN;

	/*Creates a new active connect control message*/
    paccept = (espconn_msg *)os_zalloc(sizeof(espconn_msg));
    tcp_arg(pcb, paccept);

	if (paccept == NULL)
		return ERR_MEM;
	/*Insert the node to the active connection list*/
	espconn_list_creat(&plink_active, paccept);

    paccept->preverse = espconn;
	paccept->pespconn = (struct espconn *)os_zalloc(sizeof(struct espconn));
	if (paccept->pespconn == NULL)
		return ERR_MEM;
	paccept->pespconn->proto.tcp = (esp_tcp *)os_zalloc(sizeof(esp_tcp));
	if (paccept->pespconn->proto.tcp == NULL)
		return ERR_MEM;

	/*Reserve the remote information for current active connection*/
	paccept->pcommon.pcb = pcb;

	paccept->pcommon.remote_port = pcb->remote_port;
	paccept->pcommon.remote_ip[0] = ip4_addr1_16(&pcb->remote_ip);
	paccept->pcommon.remote_ip[1] = ip4_addr2_16(&pcb->remote_ip);
	paccept->pcommon.remote_ip[2] = ip4_addr3_16(&pcb->remote_ip);
	paccept->pcommon.remote_ip[3] = ip4_addr4_16(&pcb->remote_ip);
	paccept->pcommon.write_flag = true;

	os_memcpy(espconn->proto.tcp->remote_ip, paccept->pcommon.remote_ip, 4);
	espconn->proto.tcp->remote_port = pcb->remote_port;
	espconn->state = ESPCONN_CONNECT;
	espconn_copy_partial(paccept->pespconn, espconn);

	/*Set the specify function that should be called
	 * when TCP data has been successfully delivered,
	 * when active connection receives data,
	 * or periodically from active connection*/
	tcp_sent(pcb, espconn_server_sent);
	tcp_recv(pcb, espconn_server_recv);
	tcp_poll(pcb, espconn_server_poll, 8); /* every 1 seconds */
	/*Disable Nagle algorithm default*/
	tcp_nagle_disable(pcb);
	/*Default set the total number of espconn_buf on the unsent lists for one*/
	espconn_tcp_set_buf_count(paccept->pespconn, 1);

	if (paccept->pespconn->proto.tcp->connect_callback != NULL) {
		paccept->pespconn->proto.tcp->connect_callback(paccept->pespconn);
	}

	/*Enable keep alive option*/
	if (espconn_keepalive_disabled(paccept))
		espconn_keepalive_enable(pcb);

    return ERR_OK;
}
コード例 #21
0
ファイル: modlwip.c プロジェクト: opensourcekids/micropython
STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
    lwip_socket_obj_t *socket = self_in;

    if (socket->pcb == NULL) {
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF)));
    }
    if (socket->type != MOD_NETWORK_SOCK_STREAM) {
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EOPNOTSUPP)));
    }
    // I need to do this because "tcp_accepted", later, is a macro.
    struct tcp_pcb *listener = (struct tcp_pcb*)socket->pcb;
    if (listener->state != LISTEN) {
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL)));
    }

    // accept incoming connection
    if (socket->incoming == NULL) {
        if (socket->timeout != -1) {
            for (mp_uint_t retries = socket->timeout / 100; retries--;) {
                mp_hal_delay_ms(100);
                if (socket->incoming != NULL) break;
            }
            if (socket->incoming == NULL) {
                nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ETIMEDOUT)));
            }
        } else {
            while (socket->incoming == NULL) {
                mp_hal_delay_ms(100);
            }
        }
    }

    // create new socket object
    lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t);
    socket2->base.type = (mp_obj_t)&lwip_socket_type;

    // We get a new pcb handle...
    socket2->pcb = socket->incoming;
    socket->incoming = NULL;

    // ...and set up the new socket for it.
    socket2->domain = MOD_NETWORK_AF_INET;
    socket2->type = MOD_NETWORK_SOCK_STREAM;
    socket2->incoming = NULL;
    socket2->timeout = socket->timeout;
    socket2->connected = 2;
    socket2->leftover_count = 0;
    tcp_arg((struct tcp_pcb*)socket2->pcb, (void*)socket2);
    tcp_err((struct tcp_pcb*)socket2->pcb, _lwip_tcp_error);
    tcp_recv((struct tcp_pcb*)socket2->pcb, _lwip_tcp_recv);

    tcp_accepted(listener);

    // make the return value
    uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
    memcpy(ip, &(((struct tcp_pcb*)socket2->pcb)->remote_ip), 4);
    mp_uint_t port = (mp_uint_t)((struct tcp_pcb*)socket2->pcb)->remote_port;
    mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);
    client->items[0] = socket2;
    client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);

    return client;
}
コード例 #22
0
ファイル: api_msg.c プロジェクト: spindance/lwip
/**
 * Internal helper function to close a TCP netconn: since this sometimes
 * doesn't work at the first attempt, this function is called from multiple
 * places.
 *
 * @param conn the TCP netconn to close
 */
static void
do_close_internal(struct netconn *conn)
{
  LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("Begin do_close_internal conn=%08x conn->pcb.tcp=%08x localport=%d remoteip=%08x remoteport=%d\n", conn, conn->pcb.tcp, conn->pcb.tcp->local_port, conn->pcb.tcp->remote_ip, conn->pcb.tcp->remote_port));
  err_t err;
  u8_t shut, shut_rx, shut_tx, close;

  LWIP_ASSERT("invalid conn", (conn != NULL));
  LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
  LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
  LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
  LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);

  shut = conn->current_msg->msg.sd.shut;
  shut_rx = shut & NETCONN_SHUT_RD;
  shut_tx = shut & NETCONN_SHUT_WR;
  /* shutting down both ends is the same as closing */
  close = shut == NETCONN_SHUT_RDWR;

  /* Set back some callback pointers */
  if (close) {
    tcp_arg(conn->pcb.tcp, NULL);
  }
  if (conn->pcb.tcp->state == LISTEN) {
    tcp_accept(conn->pcb.tcp, NULL);
  } else {
    /* some callbacks have to be reset if tcp_close is not successful */
    if (shut_rx) {
      tcp_recv(conn->pcb.tcp, NULL);
      tcp_accept(conn->pcb.tcp, NULL);
    }
    if (shut_tx) {
      tcp_sent(conn->pcb.tcp, NULL);
    }
    if (close) {
      tcp_poll(conn->pcb.tcp, NULL, 4);
      tcp_err(conn->pcb.tcp, NULL);
    }
  }
  /* Try to close the connection */
  if (close) {
    LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("close:calling tcp_close conn=%08x conn->pcb.tcp=%08x\n", conn, conn->pcb.tcp));
    err = tcp_close(conn->pcb.tcp);
  } else {
    LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("close:shutdown:calling tcp_shutdown conn=%08x conn->pcb.tcp=%08x\n", conn, conn->pcb.tcp));
    err = tcp_shutdown(conn->pcb.tcp, shut_rx, shut_tx);
  }
  int close_always_returns = 0;
  #if defined ALII_4573_CLOSE_ALWAYS_RETURNS && ALII_4573_CLOSE_ALWAYS_RETURNS
    close_always_returns = 1;
  #endif
  if ((close_always_returns)||(err == ERR_OK)) {

    LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("Closing succeeded conn=%08x conn->pcb.tcp=%08x err=%d\n", conn, conn->pcb.tcp, err));
    /* Closing succeeded */
    conn->current_msg->err = err;
    conn->current_msg = NULL;
    conn->state = NETCONN_NONE;
    if (close) {
      /* Set back some callback pointers as conn is going away */
      conn->pcb.tcp = NULL;
      /* Trigger select() in socket layer. Make sure everybody notices activity
       on the connection, error first! */
      API_EVENT(conn, NETCONN_EVT_ERROR, 0);
    }
    if (shut_rx) {
      API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
    }
    if (shut_tx) {
      API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
    }
    /* wake up the application task */
    LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("wake up the application task conn=%08x conn->pcb.tcp=%08x NETCONN_EVT_SENDPLUS\n", conn, conn->pcb.tcp));
    conn_op_completed(conn);
  } else {
    /* Closing failed, restore some of the callbacks */
    /* Closing of listen pcb will never fail! */
    LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("close failed conn=%08x conn->pcb.tcp=%08x\n", conn, conn->pcb.tcp));
    LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN));
    tcp_sent(conn->pcb.tcp, sent_tcp);
    tcp_poll(conn->pcb.tcp, poll_tcp, 4);
    tcp_err(conn->pcb.tcp, err_tcp);
    tcp_arg(conn->pcb.tcp, conn);
    /* don't restore recv callback: we don't want to receive any more data */
  }
  /* If closing didn't succeed, we get called again either
     from poll_tcp or from sent_tcp */
  LWIP_DEBUGF(ALII_4573_CLOSE_DEBUG, ("End do_close_internal conn=%08x conn->pcb.tcp=%08x\n", conn, conn->pcb.tcp));
}