Example #1
0
/* 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);
}
Example #2
0
/* 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
}