示例#1
0
文件: mysock.c 项目: XilunWu/cs536
/* destroy a connection context previously created with allocate_context().
 * this is invoked only if and when the network and transport threads are
 * done.
 */
void _mysock_free_context(mysock_context_t *ctx)
{
    int sd;

    assert(ctx);

    PTHREAD_CALL(pthread_cond_destroy(&ctx->blocking_cond));
    PTHREAD_CALL(pthread_mutex_destroy(&ctx->blocking_lock));

    PTHREAD_CALL(pthread_cond_destroy(&ctx->data_ready_cond));
    PTHREAD_CALL(pthread_mutex_destroy(&ctx->data_ready_lock));

    /* free any last buffers that might be lying around (e.g. retransmitted
     * packets from the peer).  normally, the application from/to queues
     * should be empty by this point; the network receive queue may
     * legitimately have retransmitted packets, so silently discard these.
     */
    (void) _mysock_free_queue(ctx, &ctx->network_recv_queue);
    (void) _mysock_free_queue(ctx, &ctx->app_recv_queue);
    (void) _mysock_free_queue(ctx, &ctx->app_send_queue);

    _network_close(&ctx->network_state);

    /* clear mysocket descriptor table entry */
    sd = ctx->my_sd;
    if (global_ctx[sd] == ctx)
        global_ctx[sd] = 0;

    memset(ctx, 0, sizeof(*ctx));
    free(ctx);
}
示例#2
0
static int _tcp_connect(network_context_t *ctx)
{
    network_context_socket_tcp_t *tcp_io_ctx;

    assert(ctx);

    tcp_io_ctx = (network_context_socket_tcp_t *) ctx->impl_data;
    assert(tcp_io_ctx);

    PTHREAD_CALL(pthread_mutex_lock(&tcp_io_ctx->connect_lock));
    if (!tcp_io_ctx->connected)
    {
        assert(ctx->peer_addr_valid);
        assert(ctx->peer_addr.sa_family == AF_INET);
        assert(((struct sockaddr_in *) &ctx->peer_addr)->sin_port > 0);

        DEBUG_LOG(("_tcp_connect (my_sd=%d): connecting on socket %d...\n",
                   tcp_io_ctx->sock_ctx->my_sd, (int)GET_SOCKET(ctx)));
        if ((connect(GET_SOCKET(ctx), &ctx->peer_addr,
                     sizeof(ctx->peer_addr))) < 0)
        {
            perror("connect (_tcp_connect)");
            fprintf(stderr, "(errno=%d)\n", errno);
            return -1;
        }

        tcp_io_ctx->connected = TRUE;
    }
    PTHREAD_CALL(pthread_mutex_unlock(&tcp_io_ctx->connect_lock));

    return 0;
}
示例#3
0
文件: mysock.c 项目: XilunWu/cs536
/* remove one packet from the head of the waiting packet queue, copying the
 * packet's payload into the specified buffer.  returns the number of bytes
 * copied.  if remove_partial is true, and there is insufficient room in the
 * destination buffer for the packet at the head of the queue, it is only
 * partially dequeued, and the remaining contents remain at the queue's head
 * for a subsequent call to dequeue_buffer().
 */
size_t _mysock_dequeue_buffer(mysock_context_t *ctx,
                              packet_queue_t   *pq,
                              void             *dst,
                              size_t            max_len,
                              bool_t            remove_partial)
{
    packet_queue_node_t *node;
    size_t               packet_len;

    assert(ctx && pq && dst);

    /* block until queue is non-empty */
    PTHREAD_CALL(pthread_mutex_lock(&ctx->data_ready_lock));
    while (!pq->head)
    {
        PTHREAD_CALL(pthread_cond_wait(&ctx->data_ready_cond,
                                       &ctx->data_ready_lock));
    }

    node = pq->head;
    assert(node && node->data);

    if (node->data_len > max_len && remove_partial)
    {
        /* remove only a portion of the packet at the head of the queue,
         * leaving the rest around for the next call to dequeue_buffer().
         */
        PTHREAD_CALL(pthread_mutex_unlock(&ctx->data_ready_lock));

        memcpy(dst, node->data, max_len);
        memmove(node->data, node->data + max_len, node->data_len - max_len);
        node->data_len -= max_len;
        packet_len = max_len;
    }
    else
    {
        /* dequeue the entire packet at the head of the queue */
        if (!(pq->head = pq->head->next))
        {
            assert(pq->tail == node);
            pq->tail = NULL;
        }
        PTHREAD_CALL(pthread_mutex_unlock(&ctx->data_ready_lock));

        memcpy(dst, node->data, MIN(max_len, node->data_len));
        packet_len = node->data_len;

        free(node->data);

        memset(node, 0, sizeof(*node));
        free(node);
    }

    return packet_len;
}
示例#4
0
文件: mysock.c 项目: XilunWu/cs536
/* create a detached thread */
pthread_t _mysock_create_thread(void *(*start)(void *args), void *args,
                                bool_t create_detached)
{
    pthread_t thread_id;

    assert(start);
    PTHREAD_CALL(pthread_create(&thread_id, NULL, start, args));
    if (create_detached)
        PTHREAD_CALL(pthread_detach(thread_id));

    return thread_id;
}
示例#5
0
文件: mysock.c 项目: XilunWu/cs536
/* transport layer thread; transport_init() should not return until the
 * transport layer finishes (i.e. the connection is over).
 */
static void *transport_thread_func(void *arg_ptr)
{
    mysock_context_t *ctx = (mysock_context_t *) arg_ptr;
    char eof_packet;

    assert(ctx);
    ASSERT_VALID_MYSOCKET_DESCRIPTOR(ctx, ctx->my_sd);

    /* enter the STCP control loop.  transport_init() doesn't return until the
     * connection's finished.  that function should first signal establishment
     * of the connection after SYN/SYN-ACK (or an error condition if the
     * connection couldn't be established) to the application by using
     * stcp_unblock_application(); as the name suggests, this unblocks the
     * calling code.  transport_init() then handles the connection,
     * returning only after the connection is closed.
     */
    transport_init(ctx->my_sd, ctx->is_active);

    /* transport_init() has returned; both sides have closed the connection,
     * do some final cleanup here...
     */

    PTHREAD_CALL(pthread_mutex_lock(&ctx->blocking_lock));
    if (ctx->blocking)
    {
        /* if we're still blocked, STCP must not have indicated the
         * connection completed.  pass the error up to the application.
         */
        if (errno == 0 || errno == EINTR)
        {
            /* this is a bit of a kludge--this should really be set by STCP
             * itself, but it's a reasonable guess if for some reason (e.g.
             * oversight) the transport layer hasn't announced why it
             * bailed out...
             */
            errno = (ctx->is_active) ? ECONNREFUSED : ECONNABORTED;
        }
        PTHREAD_CALL(pthread_mutex_unlock(&ctx->blocking_lock));
        stcp_unblock_application(ctx->my_sd);
    }
    else
    {
        PTHREAD_CALL(pthread_mutex_unlock(&ctx->blocking_lock));
    }

    /* force final myread() to return 0 bytes (this should have been done
     * by the transport layer already in response to the peer's FIN).
     */
    _mysock_enqueue_buffer(ctx, &ctx->app_send_queue, &eof_packet, 0);
    return NULL;
}
示例#6
0
文件: mysock.c 项目: XilunWu/cs536
int _mysock_wait_for_connection(mysock_context_t *ctx)
{
    assert(ctx);

    /* block until we either connect to the peer, or hit an error */
    PTHREAD_CALL(pthread_mutex_lock(&ctx->blocking_lock));
    while (ctx->blocking)
    {
        PTHREAD_CALL(pthread_cond_wait(&ctx->blocking_cond,
                                       &ctx->blocking_lock));
    }
    PTHREAD_CALL(pthread_mutex_unlock(&ctx->blocking_lock));

    return (errno = ctx->stcp_errno) ? -1 : 0;
}
示例#7
0
/* called by mylisten() to specify the number of pending connection
 * requests permitted for a listening socket.  a backlog of zero
 * specifies at most one pending connection is permitted for the socket.
 */
void _mysock_set_backlog(mysock_context_t *ctx, unsigned int backlog)
{
    unsigned int k, max_len = backlog + 1;
    uint16_t local_port;
    listen_queue_t *q;

    assert(ctx && ctx->listening && ctx->bound);

    local_port = ntohs(_network_get_port(&ctx->network_state));
    assert(local_port > 0);

    PTHREAD_CALL(pthread_rwlock_wrlock(&listen_lock));
    if ((q = _get_connection_queue(ctx)) == NULL)
    {
        /* first backlog specified for new listening socket */
        DEBUG_LOG(("allocating connection queue for local port %hu\n",
                   local_port));

        q = (listen_queue_t *) calloc(1, sizeof(listen_queue_t));
        assert(q);

        q->local_port = local_port;

        PTHREAD_CALL(pthread_cond_init(&q->connection_cond, NULL));
        PTHREAD_CALL(pthread_mutex_init(&q->connection_lock, NULL));
        HASH_INSERT(listen_table, ctx->my_sd, q);
    }

    assert(q);
    assert(q->local_port == local_port);

    if (max_len > q->max_len)
    {
        q->connection_queue = (connect_request_t *)
            realloc(q->connection_queue,
                    max_len * sizeof(connect_request_t));
        assert(q->connection_queue);

        memset(q->connection_queue + q->max_len, 0,
               (max_len - q->max_len) * sizeof(connect_request_t));
    }

    for (k = q->max_len; k < max_len; ++k)
        q->connection_queue[k].sd = -1;
    q->max_len = max_len;

    PTHREAD_CALL(pthread_rwlock_unlock(&listen_lock));
}
示例#8
0
void _mysock_passive_connection_complete(mysock_context_t *ctx)
{
    listen_queue_t *q;

    assert(ctx);

    PTHREAD_CALL(pthread_rwlock_rdlock(&listen_lock));
    assert(ctx->listen_sd >= 0);
    if ((q = _get_connection_queue(_mysock_get_context(ctx->listen_sd))))
    {
        completed_connect_t *tail, *new_entry;
        connect_request_t *connection_req = NULL;
        unsigned int k;

        /* find this connection in the incomplete connection queue */
        for (k = 0; k < q->max_len && !connection_req; ++k)
        {
            if (q->connection_queue[k].sd == ctx->my_sd)
                connection_req = &q->connection_queue[k];
        }

        assert(connection_req);

        new_entry = (completed_connect_t *)malloc(sizeof(completed_connect_t));
        assert(new_entry);

        new_entry->request = connection_req;
        new_entry->next = NULL;

        PTHREAD_CALL(pthread_mutex_lock(&q->connection_lock));

        /* add established connection to tail of completed connection queue */
        for (tail = q->completed_queue; tail && tail->next; tail = tail->next)
            ;

        if (tail)
            tail->next = new_entry;
        else
            q->completed_queue = new_entry;

        PTHREAD_CALL(pthread_mutex_unlock(&q->connection_lock));
        PTHREAD_CALL(pthread_cond_signal(&q->connection_cond));
    }
    PTHREAD_CALL(pthread_rwlock_unlock(&listen_lock));
}
示例#9
0
/* called by myaccept() to grab the first completed connection off the
 * given mysocket's connection queue, or block until one completes.
 */
void _mysock_dequeue_connection(mysock_context_t  *accept_ctx,
                                mysock_context_t **new_ctx)
{
    listen_queue_t *q;
    completed_connect_t *r;

    assert(accept_ctx && new_ctx);
    assert(accept_ctx->listening && accept_ctx->bound);

    DEBUG_LOG(("waiting for new connection...\n"));
    PTHREAD_CALL(pthread_rwlock_rdlock(&listen_lock));
    q = _get_connection_queue(accept_ctx);
    assert(q);

    PTHREAD_CALL(pthread_mutex_lock(&q->connection_lock));
    while (!q->completed_queue)
    {
        PTHREAD_CALL(pthread_cond_wait(&q->connection_cond,
                                       &q->connection_lock));
    }

    r = q->completed_queue;
    q->completed_queue = q->completed_queue->next;

    DEBUG_LOG(("dequeueing established connection from %s:%hu\n",
               inet_ntoa(((struct sockaddr_in *)
                          &r->request->peer_addr)->sin_addr),
               ntohs(((struct sockaddr_in *)
                      &r->request->peer_addr)->sin_port)));

    assert(r->request);
    *new_ctx = _mysock_get_context(r->request->sd);
    assert(*new_ctx);

    /* free up this entry from the listen queue */
    INVALIDATE_CONNECT_REQUEST(r->request);
    memset(r, 0, sizeof(*r));
    free(r);

    assert(q->cur_len > 0);
    --q->cur_len;

    PTHREAD_CALL(pthread_mutex_unlock(&q->connection_lock));
    PTHREAD_CALL(pthread_rwlock_unlock(&listen_lock));
}
示例#10
0
/* TODO: pass in errno as argument.  several libc calls on Solaris set this
 * even on successful operation.
 */
void stcp_unblock_application(mysocket_t sd)
{
    mysock_context_t *ctx = _mysock_get_context(sd);

    /* pthread_mutex_lock sometimes sets errno even on successful operation */
    int stcp_errno = errno;

    PTHREAD_CALL(pthread_mutex_lock(&ctx->blocking_lock));
    assert(ctx->blocking);
    ctx->blocking = FALSE;
    if ((ctx->stcp_errno = stcp_errno) == EINTR)
        ctx->stcp_errno = 0;
    PTHREAD_CALL(pthread_mutex_unlock(&ctx->blocking_lock));
    PTHREAD_CALL(pthread_cond_signal(&ctx->blocking_cond));

    if (!ctx->is_active)
    {
        /* move from incomplete to completed connection queue */
        _mysock_passive_connection_complete(ctx);
    }
}
示例#11
0
/* called by myclose() on a passive socket */
void _mysock_close_passive_socket(mysock_context_t *ctx)
{
    listen_queue_t *q;

    assert(ctx && ctx->listening && ctx->bound);

    PTHREAD_CALL(pthread_rwlock_wrlock(&listen_lock));
    if ((q = _get_connection_queue(ctx)) != NULL)
    {
        /* close any queued connections that haven't been passed up to the
         * user via myaccept()...
         */
        unsigned int k;
        completed_connect_t *connect_iter;

        for (k = 0; k < q->max_len; ++k)
        {
            if (q->connection_queue[k].sd != -1)
                myclose(q->connection_queue[k].sd);
        }
        free(q->connection_queue);

        for (connect_iter = q->completed_queue; connect_iter; )
        {
            /* note: socket was closed by the preceding loop */
            completed_connect_t *next = connect_iter->next;
            free(connect_iter);
            connect_iter = next;
        }

        PTHREAD_CALL(pthread_cond_destroy(&q->connection_cond));
        PTHREAD_CALL(pthread_mutex_destroy(&q->connection_lock));

        HASH_DELETE(listen_table, ctx->my_sd);
        memset(q, 0, sizeof(*q));
        free(q);
    }
    PTHREAD_CALL(pthread_rwlock_unlock(&listen_lock));
}
示例#12
0
文件: mysock.c 项目: XilunWu/cs536
/* allocate a new connection context.  this keeps track of the working state
 * between the transport and network layers for a particular connection.  the
 * context is subsequently freed on the network layer's exit.
 */
static mysock_context_t *_mysock_allocate_context(void)
{
    mysock_context_t *ctx = 0;

    ctx = (mysock_context_t *) calloc(1, sizeof(mysock_context_t));
    assert(ctx);

    /* by default, sockets are active */
    ctx->listen_sd = -1;

    /* initialise connection condition variable.  this is signaled when the
     * connection is established, i.e. myconnect() or myaccept() should
     * unblock and return to the calling application.
     */
    PTHREAD_CALL(pthread_cond_init(&ctx->blocking_cond, NULL));
    PTHREAD_CALL(pthread_mutex_init(&ctx->blocking_lock, NULL));

    /* initialise data ready condition variable.  this is signaled when
     * data is ready from the application or the network.
     */
    PTHREAD_CALL(pthread_cond_init(&ctx->data_ready_cond, NULL));
    PTHREAD_CALL(pthread_mutex_init(&ctx->data_ready_lock, NULL));

    ctx->blocking = TRUE;   /* we unblock once we're connected */


    /* initialise underlying network state.  this includes creating the actual
     * socket used for communication to the peer--this is analogous to the
     * underlying raw IP socket used by a real TCP implementation.
     */
    if (_network_init(ctx, &ctx->network_state) < 0)
    {
        _mysock_free_context(ctx);
        return NULL;
    }

    return ctx;
}
示例#13
0
/* close the given mysocket.  note that the semantics of myclose() differ
 * slightly from a regular close(); STCP doesn't implement WAIT_TIME, so
 * myclose() simply discards all knowledge of the connection once the
 * connection is terminated.
 */
int myclose(mysocket_t sd)
{
    mysock_context_t *ctx = _mysock_get_context(sd);

    DEBUG_LOG(("***myclose(%d)***\n", sd));
    MYSOCK_CHECK(ctx != NULL, EBADF);

    /* stcp_wait_for_event() needs to wake up on a socket close request */
    PTHREAD_CALL(pthread_mutex_lock(&ctx->data_ready_lock));
    ctx->close_requested = TRUE;
    PTHREAD_CALL(pthread_mutex_unlock(&ctx->data_ready_lock));
    PTHREAD_CALL(pthread_cond_broadcast(&ctx->data_ready_cond));

    /* block until STCP thread exits */
    if (ctx->transport_thread_started)
    {
        assert(!ctx->listening);
        assert(ctx->is_active || ctx->listen_sd != -1);
        PTHREAD_CALL(pthread_join(ctx->transport_thread, NULL));
        ctx->transport_thread_started = FALSE;
    }

    _network_stop_recv_thread(ctx);

    if (ctx->listening)
    {
        /* remove entry from SYN demultiplexing table */
        _mysock_close_passive_socket(ctx);
    }

    /* free all resources associated with this mysocket */
    _mysock_free_context(ctx);

    DEBUG_LOG(("myclose(%d) returning...\n", sd));
    return 0;
}
示例#14
0
文件: mysock.c 项目: XilunWu/cs536
/* add an incoming buffer (packet) to a queue for this connection; it will be
 * dequeued by stcp_network_recv() or myread() when the transport layer or
 * application is ready to use it, depending on the queue to which
 * the buffer (or packet) is added.
 *
 * in the interest of simplicity (and since we aren't writing a high
 * performance TCP stack), this just copies the specified buffer for its own
 * use, so the calling code can do whatever it wants with the packet
 * afterwards.  the copied buffer is freed later by dequeue_buffer().
 */
void _mysock_enqueue_buffer(mysock_context_t *ctx,
                            packet_queue_t   *pq,
                            const void       *packet,
                            size_t            packet_len)
{
    packet_queue_node_t *node;

    assert(ctx && pq && (packet || !packet_len));

    node = (packet_queue_node_t *) calloc(1, sizeof(packet_queue_node_t));
    assert(node);

    node->data = (char *) malloc(packet_len * sizeof(char));
    assert(node->data);

    if (packet_len > 0)
        memcpy(node->data, packet, packet_len);
    node->data_len = packet_len;

    PTHREAD_CALL(pthread_mutex_lock(&ctx->data_ready_lock));
    if (!pq->head)
    {
        assert(!pq->tail);
        pq->head = pq->tail = node;
    }
    else
    {
        assert(pq->tail);
        assert(!pq->tail->next);
        assert(!node->next);
        pq->tail->next = node;
        pq->tail = node;
    }
    PTHREAD_CALL(pthread_mutex_unlock(&ctx->data_ready_lock));
    PTHREAD_CALL(pthread_cond_broadcast(&ctx->data_ready_cond));
}
示例#15
0
void _network_close(network_context_t *ctx)
{
    network_context_socket_tcp_t *tcp_io_ctx;

    assert(ctx);

    tcp_io_ctx = (network_context_socket_tcp_t *) ctx->impl_data;
    assert(tcp_io_ctx);

    if (tcp_io_ctx->new_socket != -1)
    {
        DEBUG_LOG(("closing TCP network layer socket %d...\n",
                   (int) tcp_io_ctx->new_socket));
        closesocket(tcp_io_ctx->new_socket);
    }

    PTHREAD_CALL(pthread_mutex_destroy(&tcp_io_ctx->connect_lock));

    _network_close_socket(ctx);
}
示例#16
0
/* initialise the network subsystem.  this function should be called before
 * making use of any of the other network layer functions.
 */
int _network_init(mysock_context_t *sock_ctx, network_context_t *net_ctx)
{
    network_context_socket_tcp_t *tcp_io_ctx;
    int rc;

    assert(sock_ctx && net_ctx);
    if ((rc = _network_init_socket(sock_ctx,
                                   net_ctx,
                                   SOCK_STREAM,
                                   sizeof(network_context_socket_tcp_t))) < 0)
        return rc;

    tcp_io_ctx = (network_context_socket_tcp_t *) net_ctx->impl_data;
    assert(tcp_io_ctx);

    tcp_io_ctx->sock_ctx = sock_ctx;
    tcp_io_ctx->new_socket = -1;
    tcp_io_ctx->connected = FALSE;

    PTHREAD_CALL(pthread_mutex_init(&tcp_io_ctx->connect_lock, NULL));

    return 0;
}
示例#17
0
/* called by the transport layer to wait for new data, either from the network
 * or from the application, or for the application to request that the
 * mysocket be closed, depending on the value of flags.  abstime is the
 * absolute time at which the function should quit waiting; if NULL, it blocks
 * indefinitely until data arrives.
 *
 * sd is the mysocket descriptor for the connection of interest.
 *
 * returns bit vector corresponding to application/network data being ready,
 * of the same format as the flags passed (see the enum in stcp_api.h).
 */
unsigned int stcp_wait_for_event(mysocket_t             sd,
                                 unsigned int           flags,
                                 const struct timespec *abstime)
{
    unsigned int rc = 0;
    mysock_context_t *ctx = _mysock_get_context(sd);

    PTHREAD_CALL(pthread_mutex_lock(&ctx->data_ready_lock));
    for (;;)
    {
        if ((flags & APP_DATA) && (ctx->app_recv_queue.head != NULL))
            rc |= APP_DATA;

        if ((flags & NETWORK_DATA) && (ctx->network_recv_queue.head != NULL))
            rc |= NETWORK_DATA;

        if (/*(flags & APP_CLOSE_REQUESTED) &&*/
            ctx->close_requested && (ctx->app_recv_queue.head == NULL))
        {
            /* we should only wake up on this event once.  also, we don't
             * pass the close event down to STCP until we've already passed
             * it all outstanding data from the app.
             */
            ctx->close_requested = FALSE;
            rc |= APP_CLOSE_REQUESTED;
        }

        if (rc)
            break;

        if (abstime)
        {
            /* wait with timeout */
            switch (pthread_cond_timedwait(&ctx->data_ready_cond,
                                           &ctx->data_ready_lock,
                                           abstime))
            {
            case 0: /* some data might be available */
            case EINTR:
                break;

            case ETIMEDOUT: /* no data arrived in the specified time */
                goto done;

            case EINVAL:
                assert(0);
                break;

            default:
                assert(0);
                break;
            }
        }
        else
        {
            /* block indefinitely */
            PTHREAD_CALL(pthread_cond_wait(&ctx->data_ready_cond,
                                           &ctx->data_ready_lock));
        }
    }

done:
    PTHREAD_CALL(pthread_mutex_unlock(&ctx->data_ready_lock));

    return rc;
}
示例#18
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
}