示例#1
0
void stcp_fin_received(mysocket_t sd)
{
    mysock_context_t *ctx = _mysock_get_context(sd);
    assert(ctx);
    DEBUG_LOG(("stcp_fin_received(%d):  setting eof flag\n", sd));
    _mysock_enqueue_buffer(ctx, &ctx->app_send_queue, NULL, 0);
}
示例#2
0
/* pass data up to the application for consumption by myread() */
void stcp_app_send(mysocket_t sd, const void *src, size_t src_len)
{
    mysock_context_t *ctx = _mysock_get_context(sd);
    assert(ctx && src);
    if (src_len > 0)
    {
        DEBUG_LOG(("stcp_app_send(%d):  sending %u bytes up to app\n",
                   sd, src_len));
        _mysock_enqueue_buffer(ctx, &ctx->app_send_queue, src, src_len);
    }
}
示例#3
0
int mywrite(mysocket_t sd, const void *buf, size_t buf_len)
{
    mysock_context_t *ctx = _mysock_get_context(sd);

    MYSOCK_CHECK(ctx != NULL, EBADF);
    MYSOCK_CHECK(!ctx->listening, EINVAL);

    assert(!ctx->close_requested);
    _mysock_enqueue_buffer(ctx, &ctx->app_recv_queue, buf, buf_len);

    /* XXX: all bytes are queued, irrespective of current sender window */
    return buf_len;
}
示例#4
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;
}
示例#5
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
}