libnetsock: use libchardriver
Change-Id: Ia5b780cad0b0c636db9bd866c7223da0d38ef6ea
This commit is contained in:
parent
15e83fec25
commit
4628a14fc7
3 changed files with 202 additions and 191 deletions
|
@ -118,7 +118,7 @@ int socket_open(devminor_t minor);
|
|||
|
||||
extern struct socket socket[MAX_SOCKETS];
|
||||
|
||||
void socket_request(message * m);
|
||||
void socket_request(message * m, int ipc_status);
|
||||
void mq_process(void);
|
||||
|
||||
struct socket * get_unused_sock(void);
|
||||
|
|
|
@ -42,6 +42,30 @@ char * netsock_user_name = NULL;
|
|||
|
||||
struct socket socket[MAX_SOCKETS];
|
||||
|
||||
static int netsock_open(devminor_t minor, int access, endpoint_t user_endpt);
|
||||
static int netsock_close(devminor_t minor);
|
||||
static ssize_t netsock_read(devminor_t minor, u64_t position, endpoint_t endpt,
|
||||
cp_grant_id_t grant, size_t size, int flags, cdev_id_t id);
|
||||
static ssize_t netsock_write(devminor_t minor, u64_t position,
|
||||
endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
|
||||
cdev_id_t id);
|
||||
static int netsock_ioctl(devminor_t minor, unsigned long request,
|
||||
endpoint_t endpt, cp_grant_id_t grant, int flags,
|
||||
endpoint_t user_endpt, cdev_id_t id);
|
||||
static int netsock_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id);
|
||||
static int netsock_select(devminor_t minor, unsigned int ops,
|
||||
endpoint_t endpt);
|
||||
|
||||
static struct chardriver netsock_tab = {
|
||||
.cdr_open = netsock_open,
|
||||
.cdr_close = netsock_close,
|
||||
.cdr_read = netsock_read,
|
||||
.cdr_write = netsock_write,
|
||||
.cdr_ioctl = netsock_ioctl,
|
||||
.cdr_cancel = netsock_cancel,
|
||||
.cdr_select = netsock_select
|
||||
};
|
||||
|
||||
#define recv_q_alloc() debug_malloc(sizeof(struct recv_q))
|
||||
#define recv_q_free debug_free
|
||||
|
||||
|
@ -191,107 +215,30 @@ void sock_dequeue_data_all(struct socket * sock,
|
|||
sock->recv_data_size = 0;
|
||||
}
|
||||
|
||||
static void set_reply_msg(message * m, int status)
|
||||
{
|
||||
int proc, ref;
|
||||
|
||||
proc= m->USER_ENDPT;
|
||||
ref= (int)m->IO_GRANT;
|
||||
|
||||
m->REP_ENDPT= proc;
|
||||
m->REP_STATUS= status;
|
||||
m->REP_IO_GRANT= ref;
|
||||
}
|
||||
|
||||
static void send_reply_type(message * m, int type, int status)
|
||||
{
|
||||
int result;
|
||||
|
||||
set_reply_msg(m, status);
|
||||
|
||||
m->m_type = type;
|
||||
result = send(m->m_source, m);
|
||||
if (result != OK)
|
||||
netsock_panic("unable to send (err %d)", result);
|
||||
}
|
||||
|
||||
void send_req_reply(struct sock_req * req, int status)
|
||||
{
|
||||
message m;
|
||||
int result;
|
||||
|
||||
if (status == EDONTREPLY)
|
||||
return;
|
||||
|
||||
m.m_type = DEV_REVIVE;
|
||||
m.REP_STATUS = status;
|
||||
m.REP_ENDPT = req->endpt; /* FIXME: HACK */
|
||||
m.REP_IO_GRANT = req->id;
|
||||
|
||||
result = send(req->endpt, &m);
|
||||
if (result != OK)
|
||||
netsock_panic("unable to send (err %d)", result);
|
||||
}
|
||||
|
||||
static void send_reply(message * m, int status)
|
||||
{
|
||||
debug_sock_print("status %d", status);
|
||||
send_reply_type(m, DEV_REVIVE, status);
|
||||
}
|
||||
|
||||
static void send_reply_open(message * m, int status)
|
||||
{
|
||||
debug_sock_print("status %d", status);
|
||||
send_reply_type(m, DEV_OPEN_REPL, status);
|
||||
}
|
||||
|
||||
static void send_reply_close(message * m, int status)
|
||||
{
|
||||
debug_sock_print("status %d", status);
|
||||
send_reply_type(m, DEV_CLOSE_REPL, status);
|
||||
}
|
||||
|
||||
static void sock_reply_select(struct socket * sock, endpoint_t endpt,
|
||||
unsigned selops)
|
||||
{
|
||||
int result;
|
||||
message msg;
|
||||
|
||||
debug_sock_select_print("selops %d", selops);
|
||||
|
||||
msg.m_type = DEV_SEL_REPL1;
|
||||
msg.DEV_MINOR = get_sock_num(sock);
|
||||
msg.DEV_SEL_OPS = selops;
|
||||
|
||||
result = send(endpt, &msg);
|
||||
if (result != OK)
|
||||
netsock_panic("unable to send (err %d)", result);
|
||||
chardriver_reply_task(req->endpt, req->id, status);
|
||||
}
|
||||
|
||||
void sock_select_notify(struct socket * sock)
|
||||
{
|
||||
int result;
|
||||
message msg;
|
||||
unsigned int ops;
|
||||
|
||||
debug_sock_select_print("socket num %ld", get_sock_num(sock));
|
||||
assert(sock->select_ep != NONE);
|
||||
|
||||
msg.DEV_SEL_OPS = sock->ops->select_reply(sock);
|
||||
if (msg.DEV_SEL_OPS == 0) {
|
||||
ops = sock->ops->select_reply(sock);
|
||||
if (ops == 0) {
|
||||
debug_sock_select_print("called from %p sflags 0x%x TXsz %d RXsz %d\n",
|
||||
__builtin_return_address(0), sock->flags,
|
||||
sock->buf_size, sock->recv_data_size);
|
||||
return;
|
||||
}
|
||||
|
||||
msg.m_type = DEV_SEL_REPL2;
|
||||
msg.DEV_MINOR = get_sock_num(sock);
|
||||
|
||||
debug_sock_select_print("socket num %d select result 0x%x sent",
|
||||
msg.DEV_MINOR, msg.DEV_SEL_OPS);
|
||||
result = send(sock->select_ep, &msg);
|
||||
if (result != OK)
|
||||
netsock_panic("unable to send (err %d)", result);
|
||||
chardriver_reply_select(sock->select_ep, get_sock_num(sock), ops);
|
||||
|
||||
sock_clear_select(sock);
|
||||
sock->select_ep = NONE;
|
||||
|
@ -342,119 +289,183 @@ static int socket_request_socket(struct socket * sock, struct sock_req * req)
|
|||
return r;
|
||||
}
|
||||
|
||||
void socket_request(message * m)
|
||||
static int netsock_open(devminor_t minor, int UNUSED(access),
|
||||
endpoint_t UNUSED(user_endpt))
|
||||
{
|
||||
struct socket * sock;
|
||||
return socket_open(minor);
|
||||
}
|
||||
|
||||
static int netsock_close(devminor_t minor)
|
||||
{
|
||||
struct socket *sock;
|
||||
|
||||
if (!(sock = get_sock(minor)))
|
||||
return EINVAL;
|
||||
|
||||
if (sock->ops && sock->ops->close) {
|
||||
sock->flags &= ~SOCK_FLG_OP_PENDING;
|
||||
|
||||
return sock->ops->close(sock);
|
||||
} else
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
static int netsock_request(struct socket *sock, struct sock_req *req)
|
||||
{
|
||||
char *o;
|
||||
|
||||
/*
|
||||
* If an operation is pending (blocking operation) or writing is
|
||||
* still going on and we're reading, suspend the new operation
|
||||
*/
|
||||
if ((sock->flags & SOCK_FLG_OP_PENDING) ||
|
||||
(req->type == SOCK_REQ_READ &&
|
||||
sock->flags & SOCK_FLG_OP_WRITING)) {
|
||||
if (sock->flags & SOCK_FLG_OP_READING)
|
||||
o = "READ";
|
||||
else if (sock->flags & SOCK_FLG_OP_WRITING)
|
||||
o = "WRITE";
|
||||
else
|
||||
o = "non R/W op";
|
||||
debug_sock_print("socket %ld is busy by %s flgs 0x%x\n",
|
||||
get_sock_num(sock), o, sock->flags);
|
||||
|
||||
if (mq_enqueue(req) != 0) {
|
||||
debug_sock_print("Enqueuing suspended call failed");
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
return EDONTREPLY;
|
||||
}
|
||||
|
||||
return socket_request_socket(sock, req);
|
||||
}
|
||||
|
||||
static ssize_t netsock_read(devminor_t minor, u64_t UNUSED(position),
|
||||
endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
|
||||
cdev_id_t id)
|
||||
{
|
||||
struct socket *sock;
|
||||
struct sock_req req;
|
||||
|
||||
if (!(sock = get_sock(minor)))
|
||||
return EINVAL;
|
||||
|
||||
/* Build a request record for this request. */
|
||||
req.type = SOCK_REQ_READ;
|
||||
req.minor = minor;
|
||||
req.endpt = endpt;
|
||||
req.grant = grant;
|
||||
req.size = size;
|
||||
req.flags = flags;
|
||||
req.id = id;
|
||||
|
||||
/* Process the request. */
|
||||
return netsock_request(sock, &req);
|
||||
}
|
||||
|
||||
static ssize_t netsock_write(devminor_t minor, u64_t UNUSED(position),
|
||||
endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
|
||||
cdev_id_t id)
|
||||
{
|
||||
struct socket *sock;
|
||||
struct sock_req req;
|
||||
|
||||
if (!(sock = get_sock(minor)))
|
||||
return EINVAL;
|
||||
|
||||
/* Build a request record for this request. */
|
||||
req.type = SOCK_REQ_WRITE;
|
||||
req.minor = minor;
|
||||
req.endpt = endpt;
|
||||
req.grant = grant;
|
||||
req.size = size;
|
||||
req.flags = flags;
|
||||
req.id = id;
|
||||
|
||||
/* Process the request. */
|
||||
return netsock_request(sock, &req);
|
||||
}
|
||||
|
||||
static int netsock_ioctl(devminor_t minor, unsigned long request,
|
||||
endpoint_t endpt, cp_grant_id_t grant, int flags,
|
||||
endpoint_t UNUSED(user_endpt), cdev_id_t id)
|
||||
{
|
||||
struct socket *sock;
|
||||
struct sock_req req;
|
||||
|
||||
if (!(sock = get_sock(minor)))
|
||||
return EINVAL;
|
||||
|
||||
/* Build a request record for this request. */
|
||||
req.type = SOCK_REQ_IOCTL;
|
||||
req.minor = minor;
|
||||
req.req = request;
|
||||
req.endpt = endpt;
|
||||
req.grant = grant;
|
||||
req.flags = flags;
|
||||
req.id = id;
|
||||
|
||||
/* Process the request. */
|
||||
return netsock_request(sock, &req);
|
||||
}
|
||||
|
||||
static int netsock_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
|
||||
{
|
||||
struct socket *sock;
|
||||
|
||||
if (!(sock = get_sock(minor)))
|
||||
return EDONTREPLY;
|
||||
|
||||
debug_sock_print("socket num %ld", get_sock_num(sock));
|
||||
|
||||
/* Cancel the last operation in the queue */
|
||||
if (mq_cancel(minor, endpt, id))
|
||||
return EINTR;
|
||||
|
||||
/* Cancel any ongoing blocked read */
|
||||
if ((sock->flags & SOCK_FLG_OP_PENDING) &&
|
||||
(sock->flags & SOCK_FLG_OP_READING) &&
|
||||
endpt == sock->req.endpt && id == sock->req.id) {
|
||||
sock->flags &= ~SOCK_FLG_OP_PENDING;
|
||||
return EINTR;
|
||||
}
|
||||
|
||||
/* The request may not be found. This is OK. Do not reply. */
|
||||
return EDONTREPLY;
|
||||
}
|
||||
|
||||
static int netsock_select(devminor_t minor, unsigned int ops, endpoint_t endpt)
|
||||
{
|
||||
struct socket *sock;
|
||||
int r;
|
||||
|
||||
/*
|
||||
* Select is always executed immediately and is never suspended.
|
||||
* Although, it sets actions which must be monitored
|
||||
*/
|
||||
if (!(sock = get_sock(minor)))
|
||||
return EBADF;
|
||||
|
||||
assert(sock->select_ep == NONE || sock->select_ep == endpt);
|
||||
|
||||
if (sock->ops && sock->ops->select) {
|
||||
sock->select_ep = endpt;
|
||||
r = sock->ops->select(sock, ops);
|
||||
if (!sock_select_set(sock))
|
||||
sock->select_ep = NONE;
|
||||
} else
|
||||
r = EINVAL;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void socket_request(message * m, int ipc_status)
|
||||
{
|
||||
debug_sock_print("request %d", m->m_type);
|
||||
switch (m->m_type) {
|
||||
case DEV_OPEN:
|
||||
r = socket_open(m->DEVICE);
|
||||
send_reply_open(m, r);
|
||||
return;
|
||||
case DEV_CLOSE:
|
||||
sock = get_sock(m->DEVICE);
|
||||
if (sock->ops && sock->ops->close) {
|
||||
sock->flags &= ~SOCK_FLG_OP_PENDING;
|
||||
r = sock->ops->close(sock);
|
||||
} else
|
||||
r = EINVAL;
|
||||
send_reply_close(m, r);
|
||||
return;
|
||||
case DEV_READ_S:
|
||||
case DEV_WRITE_S:
|
||||
case DEV_IOCTL_S:
|
||||
sock = get_sock(m->DEVICE);
|
||||
if (!sock) {
|
||||
send_reply(m, EINVAL);
|
||||
return;
|
||||
}
|
||||
/* Build a request record for this request. */
|
||||
req.minor = m->DEVICE;
|
||||
req.endpt = m->m_source;
|
||||
req.grant = (cp_grant_id_t) m->IO_GRANT;
|
||||
req.id = (cdev_id_t) m->IO_GRANT;
|
||||
req.flags = m->FLAGS;
|
||||
switch (m->m_type) {
|
||||
case DEV_READ_S:
|
||||
case DEV_WRITE_S:
|
||||
req.type = (m->m_type == DEV_READ_S) ?
|
||||
SOCK_REQ_READ : SOCK_REQ_WRITE;
|
||||
req.size = m->COUNT;
|
||||
break;
|
||||
case DEV_IOCTL_S:
|
||||
req.type = SOCK_REQ_IOCTL;
|
||||
req.req = m->REQUEST;
|
||||
break;
|
||||
}
|
||||
/*
|
||||
* If an operation is pending (blocking operation) or writing is
|
||||
* still going and we want to read, suspend the new operation
|
||||
*/
|
||||
if ((sock->flags & SOCK_FLG_OP_PENDING) ||
|
||||
(m->m_type == DEV_READ_S &&
|
||||
sock->flags & SOCK_FLG_OP_WRITING)) {
|
||||
char * o = "\0";
|
||||
if (sock->flags & SOCK_FLG_OP_READING)
|
||||
o = "READ";
|
||||
else if (sock->flags & SOCK_FLG_OP_WRITING)
|
||||
o = "WRITE";
|
||||
else
|
||||
o = "non R/W op";
|
||||
debug_sock_print("socket %ld is busy by %s flgs 0x%x\n",
|
||||
get_sock_num(sock), o, sock->flags);
|
||||
if (mq_enqueue(&req) != 0) {
|
||||
debug_sock_print("Enqueuing suspended "
|
||||
"call failed");
|
||||
send_reply(m, ENOMEM);
|
||||
}
|
||||
return;
|
||||
}
|
||||
sock->req = req;
|
||||
r = socket_request_socket(sock, &req);
|
||||
send_req_reply(&req, r);
|
||||
return;
|
||||
case CANCEL:
|
||||
sock = get_sock(m->DEVICE);
|
||||
printf("socket num %ld\n", get_sock_num(sock));
|
||||
debug_sock_print("socket num %ld", get_sock_num(sock));
|
||||
/* Cancel the last operation in the queue */
|
||||
if (mq_cancel(m->DEVICE, m->m_source,
|
||||
(cdev_id_t) m->IO_GRANT)) {
|
||||
send_reply(m, EINTR);
|
||||
/* ... or a blocked read */
|
||||
} else if (sock->flags & SOCK_FLG_OP_PENDING &&
|
||||
sock->flags & SOCK_FLG_OP_READING) {
|
||||
sock->flags &= ~SOCK_FLG_OP_PENDING;
|
||||
send_reply(m, EINTR);
|
||||
}
|
||||
/* The request may not be found. This is OK. Do not reply. */
|
||||
return;
|
||||
case DEV_SELECT:
|
||||
/*
|
||||
* Select is always executed immediately and is never suspended.
|
||||
* Although, it sets actions which must be monitored
|
||||
*/
|
||||
sock = get_sock(m->DEVICE);
|
||||
assert(sock->select_ep == NONE || sock->select_ep == m->m_source);
|
||||
|
||||
if (sock->ops && sock->ops->select) {
|
||||
sock->select_ep = m->m_source;
|
||||
r = sock->ops->select(sock, m->DEV_SEL_OPS);
|
||||
if (!sock_select_set(sock))
|
||||
sock->select_ep = NONE;
|
||||
} else
|
||||
r = EINVAL;
|
||||
|
||||
sock_reply_select(sock, m->m_source, r);
|
||||
return;
|
||||
default:
|
||||
netsock_error("unknown message from VFS, type %d\n",
|
||||
m->m_type);
|
||||
}
|
||||
send_reply(m, EGENERIC);
|
||||
/* Let the chardriver library decode the request for us. */
|
||||
chardriver_process(&netsock_tab, m, ipc_status);
|
||||
}
|
||||
|
||||
void mq_process(void)
|
||||
|
|
|
@ -271,7 +271,7 @@ int main(__unused int argc, __unused char ** argv)
|
|||
}
|
||||
|
||||
if (m.m_source == VFS_PROC_NR)
|
||||
socket_request(&m);
|
||||
socket_request(&m, ipc_status);
|
||||
else if (is_ipc_notify(ipc_status)) {
|
||||
switch (m.m_source) {
|
||||
case CLOCK:
|
||||
|
|
Loading…
Reference in a new issue