Exemplo n.º 1
0
/* fills in addr with current port associated with the mysocket descriptor.
 * like the regular getsockname(), this does not fill in the local IP
 * address unless it's known.
 */
int mygetsockname(mysocket_t sd, struct sockaddr *addr, socklen_t *addrlen)
{
    mysock_context_t *ctx = _mysock_get_context(sd);

    assert(addr && addrlen);

    MYSOCK_CHECK(ctx != NULL, EBADF);
    MYSOCK_CHECK(addr != NULL && addrlen != NULL, EFAULT);

    *addr = ctx->network_state.local_addr;
    assert(!addr->sa_family || addr->sa_family == AF_INET);

    addr->sa_family = AF_INET;
    ((struct sockaddr_in *) addr)->sin_port =
        _network_get_port(&ctx->network_state);

    if (ctx->network_state.peer_addr_valid)
    {
        /* XXX: if local address has been bound, and local_addr is set,
         * we probably shouldn't override it here... although this
         * shouldn't really affect anything...
         */
        ((struct sockaddr_in *) addr)->sin_addr.s_addr =
            _network_get_local_addr(&ctx->network_state);
    }

    return 0;
}
Exemplo n.º 2
0
static void _debug_print_connection(const char *msg, const char *reason,
                                    const mysock_context_t *ctx,
                                    const struct sockaddr *peer_addr)
{
    assert(msg && reason && ctx && peer_addr);
    assert(peer_addr->sa_family == AF_INET);

    DEBUG_LOG(("%s from %s:%hu for local port %hu %s\n", msg,
               inet_ntoa(((struct sockaddr_in *) peer_addr)->sin_addr),
               ntohs(((struct sockaddr_in *) peer_addr)->sin_port),
               ntohs(_network_get_port((network_context_t *)
                                       &ctx->network_state)), reason));
}
Exemplo n.º 3
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));
}
Exemplo n.º 4
0
/* stcp_network_send()
 *
 * Send data (unreliably) to the peer.
 *
 * sd           Mysocket descriptor
 * src          A pointer to the data to send
 * src_len      The length in bytes of the buffer
 *
 * This function takes data in multiple segments and sends them as a single
 * UDP datagram. The buffer and length parameters may be repeated an arbitrary
 * number of times; a NULL pointer signifies the end of buffer/length pairs.
 * For example:
 *
 * stcp_network_send(mysd, buf1, len1, buf2, len2, NULL);
 *
 * Unreliability is handled by a helper function (_network_send()); if we're
 * operating in unreliable mode, we decide in there whether to drop the
 * datagram or send it later.
 *
 * Returns the number of bytes transferred on success, or -1 on failure.
 *
 */
ssize_t stcp_network_send(mysocket_t sd, const void *src, size_t src_len, ...)
{
    mysock_context_t *ctx = _mysock_get_context(sd);
    char              packet[MAX_IP_PAYLOAD_LEN];
    size_t            packet_len;
    const void       *next_buf;
    va_list           argptr;
    struct tcphdr    *header;

    assert(ctx && src);

    assert(src_len <= sizeof(packet));
    memcpy(packet, src, src_len);
    packet_len = src_len;

    va_start(argptr, src_len);
    while ((next_buf = va_arg(argptr, const void *)))
    {
        size_t next_len = va_arg(argptr, size_t);

        assert(packet_len + next_len <= sizeof(packet));
        memcpy(packet + packet_len, next_buf, next_len);
        packet_len += next_len;
    }
    va_end(argptr);

    /* fill in fields in the TCP header that aren't handled by students */
    assert(packet_len >= sizeof(struct tcphdr));
    header = (struct tcphdr *) packet;

    header->th_sport = _network_get_port(&ctx->network_state);
    /* N.B. assert(header->th_sport > 0) fires in the UDP SYN-ACK case */

    assert(ctx->network_state.peer_addr.sa_family == AF_INET);
    header->th_dport =
        ((struct sockaddr_in *) &ctx->network_state.peer_addr)->sin_port;
    assert(header->th_dport > 0);

    header->th_sum = 0; /* set below */
    header->th_urp = 0; /* ignored */

    _mysock_set_checksum(ctx, packet, packet_len);
    return _network_send(sd, packet, packet_len);
}
Exemplo n.º 5
0
mysocket_t myaccept(mysocket_t sd, struct sockaddr *addr, int *addrlen)
{
    mysock_context_t *accept_ctx = _mysock_get_context(sd);
    mysock_context_t *ctx;

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

#ifdef DEBUG
    fprintf(stderr, "\n####Accepting a new connection at port# %hu#### "
            "(sd=%d)\n",
            ntohs(_network_get_port(&accept_ctx->network_state)), sd);
    fflush(stderr);
#endif  /*DEBUG*/

    /* the new socket is created on an incoming SYN.  block here until we
     * establish a connection, or STCP indicates an error condition.
     */
    _mysock_dequeue_connection(accept_ctx, &ctx);
    assert(ctx);

    if (!ctx->stcp_errno)
    {
        /* fill in addr, addrlen with address of peer */
        assert(ctx->network_state.peer_addr_len > 0);

        if (addr && addrlen)
        {
            *addr    = ctx->network_state.peer_addr;
            *addrlen = ctx->network_state.peer_addr_len;
        }
    }

    assert(ctx->listen_sd == sd);
    DEBUG_LOG(("***myaccept(%d) returning new sd %d***\n", sd, ctx->my_sd));
    return (errno = ctx->stcp_errno) ? -1 : ctx->my_sd;
}