/* connect to the address specified in name on the mysocket sd */ int myconnect(mysocket_t sd, struct sockaddr *name, int namelen) { mysock_context_t *ctx = _mysock_get_context(sd); MYSOCK_CHECK(ctx != NULL, EINVAL); MYSOCK_CHECK((ctx->network_state.peer_addr_len == 0), EISCONN); #ifdef DEBUG struct sockaddr_in *sin = (struct sockaddr_in *) name; fprintf(stderr, "\n####Initiating a new connection to %s:%u#### (sd=%d)\n", inet_ntoa(sin->sin_addr), ntohs(sin->sin_port), sd); fflush(stderr); #endif /*DEBUG*/ ctx->network_state.peer_addr = *name; ctx->network_state.peer_addr_len = namelen; ctx->network_state.peer_addr_valid = TRUE; /* record connection setup for demultiplexing */ if (!ctx->bound) { int rc; /* we need to find the local port number to set up demultiplexing * before we send the SYN. (this is really only required in the VNS * case--we have to demultiplex only on listening sockets for the * UDP/TCP network layer--but it doesn't do any harm here in * general). */ if ((rc = _mysock_bind_ephemeral(ctx)) < 0) return rc; } /* time for kick off */ _mysock_transport_init(sd, TRUE); /* block until connection is established, or we hit an error */ return _mysock_wait_for_connection(ctx); }
/* new connection requests for the given mysocket are queued to the * corresponding listen queue if one exists and there's sufficient * space, or dropped otherwise. ctx is the context associated with * a mysocket for which myaccept() will be called (i.e., a listening * socket). * * returns TRUE if the new connection has been queued, FALSE otherwise. */ bool_t _mysock_enqueue_connection(mysock_context_t *ctx, const void *packet, size_t packet_len, const struct sockaddr *peer_addr, int peer_addr_len, void *user_data) { listen_queue_t *q; connect_request_t *queue_entry = NULL; unsigned int k; assert(ctx && ctx->listening && ctx->bound); assert(packet && peer_addr); assert(peer_addr_len > 0); #define DEBUG_CONNECTION_MSG(msg, reason) \ _debug_print_connection(msg, reason, ctx, peer_addr) PTHREAD_CALL(pthread_rwlock_rdlock(&listen_lock)); if (packet_len < sizeof(struct tcphdr) || !(((struct tcphdr *) packet)->th_flags & TH_SYN)) { DEBUG_CONNECTION_MSG("received non-SYN packet", "(ignoring)"); goto done; /* not a connection setup request */ } if (!(q = _get_connection_queue(ctx))) { DEBUG_CONNECTION_MSG("dropping SYN packet", "(socket not listening)"); goto done; /* the socket was closed or not listening */ } /* see if this is a retransmission of an existing request */ for (k = 0; k < q->max_len; ++k) { connect_request_t *r = &q->connection_queue[k]; assert(r->sd == -1 || peer_addr_len == r->peer_addr_len); /* both are sockaddr_in */ if (!memcmp(&r->peer_addr, peer_addr, peer_addr_len)) { DEBUG_CONNECTION_MSG("dropping SYN packet", "(retransmission of queued request)"); goto done; /* retransmission */ } } /* if it's not a retransmission, find an empty slot in the incomplete * connection table */ if (q->cur_len < q->max_len) { for (k = 0; k < q->max_len && !queue_entry; ++k) { if (q->connection_queue[k].sd < 0) queue_entry = &q->connection_queue[k]; } assert(queue_entry); ++q->cur_len; } if (queue_entry) { mysock_context_t *new_ctx; /* establish the connection */ assert(queue_entry->sd == -1); if ((queue_entry->sd = _mysock_new_mysocket(ctx->network_state.is_reliable)) < 0) { DEBUG_CONNECTION_MSG("dropping SYN packet", "(couldn't allocate new mysocket)"); INVALIDATE_CONNECT_REQUEST(queue_entry); --q->cur_len; queue_entry = NULL; goto done; } new_ctx = _mysock_get_context(queue_entry->sd); new_ctx->listen_sd = ctx->my_sd; new_ctx->network_state.peer_addr = *peer_addr; new_ctx->network_state.peer_addr_len = peer_addr_len; new_ctx->network_state.peer_addr_valid = TRUE; queue_entry->peer_addr = *peer_addr; queue_entry->peer_addr_len = peer_addr_len; queue_entry->user_data = (void *) user_data; DEBUG_CONNECTION_MSG("establishing connection", ""); /* update any additional network layer state based on the initial * packet, e.g. remapped sequence numbers, etc. */ _network_update_passive_state(&new_ctx->network_state, &ctx->network_state, user_data, packet, packet_len); _mysock_transport_init(queue_entry->sd, FALSE); /* pass the SYN packet on to the main STCP code */ _mysock_enqueue_buffer(new_ctx, &new_ctx->network_recv_queue, packet, packet_len); } else { /* the packet is dropped (maximum backlog reached) */ DEBUG_CONNECTION_MSG("dropping SYN packet", "(queue full)"); } done: PTHREAD_CALL(pthread_rwlock_unlock(&listen_lock)); return (queue_entry != NULL); #undef DEBUG_CONNECTION_MSG }