bsdsocket.c

来自「Keil下移植好的lwip基于c166」· C语言 代码 · 共 608 行 · 第 1/2 页

C
608
字号
    len = min (len, tcp_sndbuf (info->pcb));
    err = tcp_write (info->pcb, s, len, 1);

    if (err == ERR_OK) {
	if (!info->pcb->unacked)
	    tcp_output (info->pcb);
	return len;
    }
    errno = lwip_error_to_errno (err);
    return -1;
}

static int socket_write_queue (void *o)
{
    struct socket_info *info = (struct socket_info *) o;
    struct tcp_seg *unsent;
    int total = 0;
    if (info->type != STREAM_MAGIC)
	return -1;
    if (!info->pcb)
	return -1;
    for (unsent = info->pcb->unsent; unsent; unsent = unsent->next)
	total += unsent->len;
    return total;
}

static int socket_write_nonblock (void *o, unsigned char *s, int len)
{
    if (socket_write_space (o, 0))
	return socket_write (o, s, len);
    errno = EAGAIN;
    return -1;
}

err_t _socket_recv (void *arg, struct tcp_pcb * pcb, struct pbuf * p, err_t err)
{
    struct socket_info *info = (struct socket_info *) arg;
    if (err == ERR_OK && p == NULL) {
	err = _socket_close (info->pcb);
printf ("_socket_recv, error\n");
	info->pcb = 0;
	return err;
    }
    if (err == ERR_OK && p != NULL) {
	char *s;
	struct pbuf *q;
	struct packet_item *j;
/* record the packet in our list for later reading */
	lappend (info->d.stream.packet_list);
	j = ltail (info->d.stream.packet_list);
	s = j->data = (char *) malloc (p->tot_len);	/* FIXME: check return value */
	j->len = p->tot_len;
	for (q = p; q; q = q->next) {
	    memcpy (s, q->payload, q->len);
	    s += q->len;
	}
	pbuf_free (p);
    }
    return ERR_OK;
}

static int socket_read (void *o, unsigned char *s, int len)
{
    struct socket_info *info = (struct socket_info *) o;
    struct packet_item *j;
    int r = 0;

    if (info->type != STREAM_MAGIC) {
	errno = ENOTSOCK;
	return -1;
    }

    if (!info->pcb) {
	errno = ENOTCONN;
	return -1;
    }

    for (;;) {
/* explicit (i.e. always one extra callback) */
	if (global_callback ()) {
	    errno = EINTR;
	    return -1;
	}
	if (!info->pcb)		/* socket closed */
	    return 0;
	if ((j = lhead (info->d.stream.packet_list)))
	    if (j->len > 0)
		break;
    }

/* FIXME: quadruple check this algorithm */
    for (;;) {
	int c;
	c = min (len, j->len - info->d.stream.in_packet_offset);
	if (!c)
	    break;		/* out of space */
	memcpy (s, j->data + info->d.stream.in_packet_offset, c);
	s += c;
	r += c;
	len -= c;
	info->d.stream.in_packet_offset += c;
	if (info->d.stream.in_packet_offset == j->len) {
	    info->d.stream.in_packet_offset = 0;
	    ldeleteinc (info->d.stream.packet_list, j);
	    if (!j)
		break;		/* nothing left to process */
	}
    }

    tcp_recved (info->pcb, r);
    tcp_output (info->pcb);

    return r;
}

static int socket_read_avail (void *o, int n)
{
    packet_item *j;
    int total = 0;

    struct socket_info *info = (struct socket_info *) o;

    if (info->type == STREAM_MAGIC) {
	if (!info->pcb)
	    return -1;
	lsearchforward (info->d.stream.packet_list, j, total += j->len);
	return total;
    }

    total = lcount (info->d.listener.incoming_list);
/* return a count of the incoming connections */
    return total;
}

static int socket_read_nonblock (void *o, unsigned char *s, int len)
{
    if (socket_read_avail (o, 0))
	return socket_read (o, s, len);
    errno = EAGAIN;
    return -1;
}

static void *socket_socket (void *param, int arg1, int arg2)
{
    struct socket_info *info;

    info = (struct socket_info *) malloc (sizeof (struct socket_info));
    if (!info) {
	errno = ENOMEM;
	return 0;
    }
    memset (info, 0, sizeof (struct socket_info));
    info->pcb = tcp_new ();
    if (!info->pcb) {
	errno = ENOMEM;
	free (info);
	return 0;
    }
    info->type = LISTENER_MAGIC;
    linit (info->d.listener.incoming_list, incoming_item, incoming_free);
    tcp_err (info->pcb, _listener_error);
    return (void *) info;
}

static err_t _socket_accept (void *arg, struct tcp_pcb *pcb, err_t err)
{
    struct socket_info *info = (struct socket_info *) arg;
    incoming_item *j;

    if (lcount (info->d.listener.incoming_list) >= info->d.listener.listener_queue_max_len)
	return ERR_ABRT;

    if (mem_usage_percent (0) > 25)
	return ERR_ABRT;

/* add a new connection to our list of pending incoming connections */
    lappend (info->d.listener.incoming_list);
    j = ltail (info->d.listener.incoming_list);
    j->s = (struct socket_info *) malloc (sizeof (struct socket_info));
    if (!j->s) {
	ldeleteinc (info->d.listener.incoming_list, j);
	return ERR_ABRT;
    }
    memset (j->s, 0, sizeof (struct socket_info));

/* setup list member structure */
    linit (j->s->d.stream.packet_list, packet_item, packet_free);
    j->s->type = STREAM_MAGIC;
    j->s->pcb = pcb;

/* tcp callbacks */
    tcp_arg (j->s->pcb, (void *) j->s);
    tcp_recv (j->s->pcb, _socket_recv);
    tcp_err (j->s->pcb, _socket_error);

    return ERR_OK;
}

static int socket_ioctl (void *o, int cmd, int *config)
{
    struct socket_info *info = (struct socket_info *) o;
    struct sockaddr_in *s = (struct sockaddr_in *) config;
    err_t r;
    switch (cmd) {
    case SIOBIND:
	if (info->type != LISTENER_MAGIC) {
	    errno = ENOTSOCK;
	    return -1;
	}
	r = tcp_bind (info->pcb, (struct ip_addr *) &s->sin_addr, ntohs (s->sin_port));
	if (r != ERR_OK) {
	    errno = lwip_error_to_errno (r);
	    return -1;
	}
	return 0;
    case SIOSHUTDOWN:
	if (info->type != STREAM_MAGIC) {
	    errno = ENOTSOCK;
	    return -1;
	}
	if (!info->pcb) {
	    errno = ENOTCONN;
	    return -1;
	}
	info->d.stream.shutdown_how |= 1 << *config;
	if (info->d.stream.shutdown_how >= (1 << *config)) {
	    _socket_close (info->pcb);
	    info->pcb = 0;
	}
	return 0;
    case SIOLISTEN:
	if (info->type != LISTENER_MAGIC) {
	    errno = ENOTSOCK;
	    return -1;
	}
	info->pcb = tcp_listen (info->pcb);
	info->d.listener.listener_queue_max_len = *config;
	tcp_arg (info->pcb, o);
	tcp_accept (info->pcb, _socket_accept);
	return 0;
    }
    errno = EINVAL;
    return -1;
}

static void *socket_accept (void *o, struct sockaddr *addr, int *addrlen)
{
    incoming_item *j;
    struct socket_info *info = (struct socket_info *) o;
    void *r;

    if (info->type != LISTENER_MAGIC) {
	errno = ENOTSOCK;
	return 0;
    }
    if (*addrlen != sizeof (struct sockaddr_in)) {
	errno = EFAULT;
	return 0;
    }

    j = lhead (info->d.listener.incoming_list);
    if (!j) {
	errno = EAGAIN;
	return 0;
    }
    while (!j->s->pcb) {
/* loop through sockets that closed before accept() could be called by the upper level application */
	ldeleteinc (info->d.listener.incoming_list, j);
	if (!j) {
	    errno = EAGAIN;
	    return 0;
	}
    }
    r = (void *) j->s;
    j->s = 0;			/* zero it so the structure doesn't get free'd */
    ldeleteinc (info->d.listener.incoming_list, j);	/* remove from listener queue */

    return r;
}

struct file file_socket = {
    socket_socket,		/* we use the open() method */
    socket_dup,
    socket_close,
    socket_ioctl,
    0,
    socket_write,
    socket_write,
    socket_write_space,
    socket_write_nonblock,
    0,
    socket_read,
    socket_read,
    socket_read_avail,
    socket_read_nonblock,
    socket_write_queue,
    0,
    0,
    socket_accept,
};

#endif	/* HAVE_NET */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?