This will put the data in the send buffer, and it will be sent when possible.
This also allows the socket to be shut down for writing before it has
reached the ESTABLISHED state.
switch(c->state) {
case CLOSED:
case LISTEN:
switch(c->state) {
case CLOSED:
case LISTEN:
- case SYN_SENT:
- case SYN_RECEIVED:
debug("Error: send() called on unconnected connection %p\n", c);
errno = ENOTCONN;
return -1;
debug("Error: send() called on unconnected connection %p\n", c);
errno = ENOTCONN;
return -1;
+ case SYN_SENT:
+ case SYN_RECEIVED:
case ESTABLISHED:
case CLOSE_WAIT:
break;
case ESTABLISHED:
case CLOSE_WAIT:
break;
+
+ // Don't send anything yet if the connection has not fully established yet
+
+ if (c->state == SYN_SENT || c->state == SYN_RECEIVED)
+ return len;
+
ack(c, false);
if(!is_reliable(c)) {
ack(c, false);
if(!is_reliable(c)) {
c->rcv.irs = hdr.seq;
c->rcv.nxt = hdr.seq;
c->rcv.irs = hdr.seq;
c->rcv.nxt = hdr.seq;
- set_state(c, ESTABLISHED);
+ if(c->shut_wr) {
+ c->snd.last++;
+ set_state(c, FIN_WAIT_1);
+ } else {
+ set_state(c, ESTABLISHED);
+ }
// TODO: notify application of this somehow.
break;
// TODO: notify application of this somehow.
break;
+ // Only process shutting down writes once.
+ if (c->shut_wr)
+ return 0;
+
+ c->shut_wr = true;
+
switch(c->state) {
case CLOSED:
case LISTEN:
switch(c->state) {
case CLOSED:
case LISTEN:
return -1;
case SYN_SENT:
return -1;
case SYN_SENT:
return 0;
case SYN_RECEIVED:
return 0;
case SYN_RECEIVED:
}
size_t utcp_get_sndbuf_free(struct utcp_connection *c) {
}
size_t utcp_get_sndbuf_free(struct utcp_connection *c) {
- if(c && (c->state == ESTABLISHED || c->state == CLOSE_WAIT)) {
+ if (!c)
+ return 0;
+
+ switch(c->state) {
+ case SYN_SENT:
+ case SYN_RECEIVED:
+ case ESTABLISHED:
+ case CLOSE_WAIT:
return buffer_free(&c->sndbuf);
return buffer_free(&c->sndbuf);
bool nodelay;
bool keepalive;
bool nodelay;
bool keepalive;
// Congestion avoidance state
// Congestion avoidance state