Example #1
0
/* takes socket at state CLOSED, and start connect to s->remote
 *      if s not CLOSED, return null
 * \return socket in connection state
 * \return      = SExxx - some error
 *
 * */
tcp_socket_t *tcp_connect_restart (tcp_socket_t *s)
{
    unsigned long optdata;
    ip_t *ip = s->ip;
    tcp_debug ("tcp reconnect to port %u\n", s->remote_port);

	s->lastack = s->snd_nxt - 1;
	s->snd_lbb = s->snd_nxt - 1;
	s->snd_wnd = TCP_WND;
	s->ssthresh = s->mss * 10;
	s->state = SYN_SENT;

	/* Build an MSS option */
	optdata = HTONL (((unsigned long)2 << 24) |
		((unsigned long)4 << 16) |
		(((unsigned long)s->mss / 256) << 8) |
		(s->mss & 255));

	if (! tcp_enqueue_option4 (s, TCP_SYN, optdata)) {
		return 0;
	}
    mutex_lock (&ip->lock);
    s->tmr = ip->tcp_ticks;
	tcp_list_add (&ip->tcp_sockets, s);
#if TCP_LOCK_STYLE <= TCP_LOCK_SURE
    tcp_output (s);
    mutex_unlock (&ip->lock);
#elif TCP_LOCK_STYLE >= TCP_LOCK_RELAXED
    mutex_unlock (&ip->lock);
    tcp_output (s);
#endif
    mutex_unlock (&s->lock);
	return s;
}
Example #2
0
/*
 * Set the state of the connection to be LISTEN, which means that it
 * is able to accept incoming connections. The protocol control block
 * is reallocated in order to consume less memory. Setting the
 * connection to LISTEN is an irreversible process.
 */
tcp_socket_t *tcp_listen (ip_t *ip, unsigned char *ipaddr,
	unsigned short port)
{
	tcp_socket_t *s, *cs;
	ip_addr targetip;
	

	if (ipaddr) {
	    targetip = ipadr_4ucs(ipaddr);
	}
	else
	    targetip.val = 0;

	s = tcp_alloc (ip);
	if (s == 0) {
		return 0;
	}

	/* Bind the connection to a local portnumber and IP address. */
	mutex_lock (&ip->lock);
	if (port == 0) {
		port = tcp_new_port (ip);
	}
	tcp_debug ("tcp_listen: port %u\n", port);

	/* Check if the address already is in use. */
	for (cs = ip->tcp_listen_sockets; cs != 0; cs = cs->next) {
		if (cs->local_port == port) {
			if ( ipadr_is_same(targetip.var, cs->local_ip) ) {
				mutex_unlock (&ip->lock);
				mem_free (s);
				return 0;
			}
		}
	}
	for (cs = ip->tcp_sockets; cs != 0; cs = cs->next) {
		if (cs->local_port == port) {
			if (ipadr_is_same(targetip.var, cs->local_ip) ) {
				mutex_unlock (&ip->lock);
				mem_free (s);
				return 0;
			}
		}
	}

	if ( ipadr_not0(targetip.var) ) {
		s->local_ip = targetip.var;
	}
	s->local_port = port;
	s->state = LISTEN;
    buf_queueh_init(&s->inq, sizeof(s->queue));

	tcp_list_add (&ip->tcp_listen_sockets, s);
	mutex_unlock (&ip->lock);
	return s;
}
Example #3
0
/*
 * Set the state of the connection to be LISTEN, which means that it
 * is able to accept incoming connections. The protocol control block
 * is reallocated in order to consume less memory. Setting the
 * connection to LISTEN is an irreversible process.
 */
tcp_socket_t *tcp_listen (ip_t *ip, unsigned char *ipaddr,
	unsigned short port)
{
	tcp_socket_t *s, *cs;

	if (! ipaddr) {
		ipaddr = (unsigned char*) "\0\0\0\0";
	}
	s = mem_alloc (ip->pool, sizeof (tcp_socket_t));
	if (s == 0) {
		return 0;
	}
	s->ip = ip;

	/* Bind the connection to a local portnumber and IP address. */
	mutex_lock (&ip->lock);
	if (port == 0) {
		port = tcp_new_port (ip);
	}
	tcp_debug ("tcp_listen: port %u\n", port);

	/* Check if the address already is in use. */
	for (cs = ip->tcp_listen_sockets; cs != 0; cs = cs->next) {
		if (cs->local_port == port) {
			if (memcmp (cs->local_ip, IP_ADDR(0), 4) == 0 ||
			    memcmp (ipaddr, IP_ADDR(0), 4) == 0 ||
			    memcmp (cs->local_ip, ipaddr, 4) == 0) {
				mutex_unlock (&ip->lock);
				mem_free (s);
				return 0;
			}
		}
	}
	for (cs = ip->tcp_sockets; cs != 0; cs = cs->next) {
		if (cs->local_port == port) {
			if (memcmp (cs->local_ip, IP_ADDR(0), 4) == 0 ||
			    memcmp (ipaddr, IP_ADDR(0), 4) == 0 ||
			    memcmp (cs->local_ip, ipaddr, 4) == 0) {
				mutex_unlock (&ip->lock);
				mem_free (s);
				return 0;
			}
		}
	}

	if (memcmp (ipaddr, IP_ADDR(0), 4) != 0) {
		memcpy (s->local_ip, ipaddr, 4);
	}
	s->local_port = port;
	s->state = LISTEN;

	tcp_list_add (&ip->tcp_listen_sockets, s);
	mutex_unlock (&ip->lock);
	return s;
}
Example #4
0
/*
 * Connect to another host. Wait until connection established.
 * Return 1 on success, 0 on error.
 */
tcp_socket_t *
tcp_connect (ip_t *ip, unsigned char *ipaddr, unsigned short port)
{
	tcp_socket_t *s;
	unsigned long optdata;

	tcp_debug ("tcp_connect to port %u\n", port);
	if (ipaddr == 0)
		return 0;
	mutex_lock (&ip->lock);

	s = tcp_alloc (ip);
	memcpy (s->remote_ip, ipaddr, 4);
	s->remote_port = port;
	if (s->local_port == 0) {
		s->local_port = tcp_new_port (ip);
	}
	s->lastack = s->snd_nxt - 1;
	s->snd_lbb = s->snd_nxt - 1;
	s->snd_wnd = TCP_WND;
	s->ssthresh = s->mss * 10;
	s->state = SYN_SENT;

	/* Build an MSS option */
	optdata = HTONL (((unsigned long)2 << 24) |
		((unsigned long)4 << 16) |
		(((unsigned long)s->mss / 256) << 8) |
		(s->mss & 255));

	if (! tcp_enqueue (s, 0, 0, TCP_SYN, (unsigned char*) &optdata, 4)) {
		mem_free (s);
		mutex_unlock (&ip->lock);
		return 0;
	}
	tcp_list_add (&ip->tcp_sockets, s);
	tcp_output (s);
	mutex_unlock (&ip->lock);

	mutex_lock (&s->lock);
	for (;;) {
		mutex_wait (&s->lock);
		if (s->state == ESTABLISHED) {
			mutex_unlock (&s->lock);
			return s;
		}
		if (s->state == CLOSED) {
			mutex_unlock (&s->lock);
			mem_free (s);
			return 0;
		}
	}
}
Example #5
0
tcp_socket_t *tcp_accept_until (tcp_socket_t *s
                                , scheduless_condition waitfor, void* waitarg)
{
	tcp_socket_t *ns;
	buf_t *p;
	ip_hdr_t *iph;
	tcp_hdr_t *h;
	unsigned long optdata;
    int ok = tcp_lock_avail(s, (1<<LISTEN)
                              , waitfor, waitarg);
    if (ok != 0){
        if (s->state != LISTEN){
            tcp_debug ("tcp_accept: called in invalid state\n");
            return (tcp_socket_t *)SEINVAL;
        }
        if (ok == -1)
            return 0;
        return (tcp_socket_t *)ok;
    }

	/* Create a new PCB, and respond with a SYN|ACK.
	 * If a new PCB could not be created (probably due to lack of memory),
	 * we don't do anything, but rely on the sender will retransmit
	 * the SYN at a time when we have more memory available. */
	mutex_lock (&s->ip->lock);
	ns = tcp_alloc (s->ip);
	if (ns == 0) {
        mutex_unlock (&s->lock);
		++(s->ip->tcp_in_discards);
		mutex_unlock (&s->ip->lock);
        tcp_debug ("tcp_accept: could not allocate PCB\n");
		return (tcp_socket_t *)SENOMEM;
	}
    p = tcp_queue_get (s);

	h = (tcp_hdr_t*) p->payload;
	iph = ((ip_hdr_t*) p->payload) - 1;

	/* Set up the new PCB. */
	ns->local_ip = iph->dest.var;
	ns->local_port = s->local_port;
	ns->remote_ip  = iph->src;
	ns->remote_port = h->src;
	ns->state = SYN_RCVD;
	ns->rcv_nxt = s->ip->tcp_input_seqno + 1;
	ns->snd_wnd = h->wnd;
	ns->ssthresh = ns->snd_wnd;
	ns->snd_wl1 = s->ip->tcp_input_seqno;
	ns->ip = s->ip;
    mutex_unlock (&s->lock);

	/* Register the new PCB so that we can begin receiving
	 * segments for it. */
	tcp_list_add (&s->ip->tcp_sockets, ns);

	/* Parse any options in the SYN. */
	tcp_parseopt (ns, h);

	/* Build an MSS option. */
	optdata = HTONL (((unsigned long)2 << 24) | ((unsigned long)4 << 16) |
		(((unsigned long)ns->mss / 256) << 8) | (ns->mss & 255));
	buf_free (p);

	/* Send a SYN|ACK together with the MSS option.
	 * there is impossible fail of tcp_enqueue_option4
	 * */
	tcp_enqueue_option4 (ns, TCP_SYN | TCP_ACK, optdata);
#if TCP_LOCK_STYLE <= TCP_LOCK_SURE
    tcp_output (ns);
    mutex_unlock (&ns->ip->lock);
#elif TCP_LOCK_STYLE >= TCP_LOCK_RELAXED
    mutex_unlock (&ns->ip->lock);
    tcp_output (ns);
#endif
    mutex_unlock (&ns->lock);
	return ns;
}
Example #6
0
tcp_socket_t *
tcp_accept (tcp_socket_t *s)
{
	tcp_socket_t *ns;
	buf_t *p;
	ip_hdr_t *iph;
	tcp_hdr_t *h;
	unsigned long optdata;
again:
	mutex_lock (&s->lock);
	for (;;) {
		if (s->state != LISTEN) {
			mutex_unlock (&s->lock);
			tcp_debug ("tcp_accept: called in invalid state\n");
			return 0;
		}
		if (! tcp_queue_is_empty (s)) {
			p = tcp_queue_get (s);
			break;
		}
		mutex_wait (&s->lock);
	}
	mutex_unlock (&s->lock);

	/* Create a new PCB, and respond with a SYN|ACK.
	 * If a new PCB could not be created (probably due to lack of memory),
	 * we don't do anything, but rely on the sender will retransmit
	 * the SYN at a time when we have more memory available. */
	mutex_lock (&s->ip->lock);
	ns = tcp_alloc (s->ip);
	if (ns == 0) {
		tcp_debug ("tcp_accept: could not allocate PCB\n");
		++s->ip->tcp_in_discards;
		mutex_unlock (&s->ip->lock);
		buf_free (p);
		goto again;
	}
	h = (tcp_hdr_t*) p->payload;
	iph = ((ip_hdr_t*) p->payload) - 1;

	/* Set up the new PCB. */
	memcpy (ns->local_ip, iph->dest, 4);
	ns->local_port = s->local_port;
	memcpy (ns->remote_ip, iph->src, 4);
	ns->remote_port = h->src;
	ns->state = SYN_RCVD;
	ns->rcv_nxt = s->ip->tcp_input_seqno + 1;
	ns->snd_wnd = h->wnd;
	ns->ssthresh = ns->snd_wnd;
	ns->snd_wl1 = s->ip->tcp_input_seqno;
	ns->ip = s->ip;

	/* Register the new PCB so that we can begin receiving
	 * segments for it. */
	tcp_list_add (&s->ip->tcp_sockets, ns);

	/* Parse any options in the SYN. */
	tcp_parseopt (ns, h);

	/* Build an MSS option. */
	optdata = HTONL (((unsigned long)2 << 24) | ((unsigned long)4 << 16) |
		(((unsigned long)ns->mss / 256) << 8) | (ns->mss & 255));
	buf_free (p);

	/* Send a SYN|ACK together with the MSS option. */
	tcp_enqueue (ns, 0, 0, TCP_SYN | TCP_ACK, (unsigned char*) &optdata, 4);
	tcp_output (ns);
	mutex_unlock (&s->ip->lock);
	return ns;
}