Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netgraph/ng_ksocket.c
Show First 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | static const struct ng_ksocket_alias ng_ksocket_protos[] = { | ||||
{ "swipe", IPPROTO_SWIPE, PF_INET }, | { "swipe", IPPROTO_SWIPE, PF_INET }, | ||||
{ "encap", IPPROTO_ENCAP, PF_INET }, | { "encap", IPPROTO_ENCAP, PF_INET }, | ||||
{ "divert", IPPROTO_DIVERT, PF_INET }, | { "divert", IPPROTO_DIVERT, PF_INET }, | ||||
{ "pim", IPPROTO_PIM, PF_INET }, | { "pim", IPPROTO_PIM, PF_INET }, | ||||
{ NULL, -1 }, | { NULL, -1 }, | ||||
}; | }; | ||||
/* Helper functions */ | /* Helper functions */ | ||||
static int ng_ksocket_check_accept(priv_p); | static int ng_ksocket_accept(priv_p); | ||||
static void ng_ksocket_finish_accept(priv_p); | |||||
static int ng_ksocket_incoming(struct socket *so, void *arg, int waitflag); | static int ng_ksocket_incoming(struct socket *so, void *arg, int waitflag); | ||||
static int ng_ksocket_parse(const struct ng_ksocket_alias *aliases, | static int ng_ksocket_parse(const struct ng_ksocket_alias *aliases, | ||||
const char *s, int family); | const char *s, int family); | ||||
static void ng_ksocket_incoming2(node_p node, hook_p hook, | static void ng_ksocket_incoming2(node_p node, hook_p hook, | ||||
void *arg1, int arg2); | void *arg1, int arg2); | ||||
/************************************************************************ | /************************************************************************ | ||||
STRUCT SOCKADDR PARSE TYPE | STRUCT SOCKADDR PARSE TYPE | ||||
▲ Show 20 Lines • Show All 527 Lines • ▼ Show 20 Lines | case NGM_KSOCKET_LISTEN: | ||||
{ | { | ||||
/* Sanity check */ | /* Sanity check */ | ||||
if (msg->header.arglen != sizeof(int32_t)) | if (msg->header.arglen != sizeof(int32_t)) | ||||
ERROUT(EINVAL); | ERROUT(EINVAL); | ||||
if (so == NULL) | if (so == NULL) | ||||
ERROUT(ENXIO); | ERROUT(ENXIO); | ||||
/* Listen */ | /* Listen */ | ||||
so->so_state |= SS_NBIO; | |||||
error = solisten(so, *((int32_t *)msg->data), td); | error = solisten(so, *((int32_t *)msg->data), td); | ||||
break; | break; | ||||
} | } | ||||
case NGM_KSOCKET_ACCEPT: | case NGM_KSOCKET_ACCEPT: | ||||
{ | { | ||||
/* Sanity check */ | /* Sanity check */ | ||||
if (msg->header.arglen != 0) | if (msg->header.arglen != 0) | ||||
ERROUT(EINVAL); | ERROUT(EINVAL); | ||||
if (so == NULL) | if (so == NULL) | ||||
ERROUT(ENXIO); | ERROUT(ENXIO); | ||||
/* Make sure the socket is capable of accepting */ | /* Make sure the socket is capable of accepting */ | ||||
if (!(so->so_options & SO_ACCEPTCONN)) | if (!(so->so_options & SO_ACCEPTCONN)) | ||||
ERROUT(EINVAL); | ERROUT(EINVAL); | ||||
if (priv->flags & KSF_ACCEPTING) | if (priv->flags & KSF_ACCEPTING) | ||||
ERROUT(EALREADY); | ERROUT(EALREADY); | ||||
error = ng_ksocket_check_accept(priv); | |||||
if (error != 0 && error != EWOULDBLOCK) | |||||
ERROUT(error); | |||||
/* | /* | ||||
* If a connection is already complete, take it. | * If a connection is already complete, take it. | ||||
* Otherwise let the upcall function deal with | * Otherwise let the upcall function deal with | ||||
* the connection when it comes in. | * the connection when it comes in. | ||||
*/ | */ | ||||
error = ng_ksocket_accept(priv); | |||||
if (error != 0 && error != EWOULDBLOCK) | |||||
ERROUT(error); | |||||
priv->response_token = msg->header.token; | priv->response_token = msg->header.token; | ||||
raddr = priv->response_addr = NGI_RETADDR(item); | raddr = priv->response_addr = NGI_RETADDR(item); | ||||
if (error == 0) { | |||||
ng_ksocket_finish_accept(priv); | |||||
} else | |||||
priv->flags |= KSF_ACCEPTING; | |||||
break; | break; | ||||
} | } | ||||
case NGM_KSOCKET_CONNECT: | case NGM_KSOCKET_CONNECT: | ||||
{ | { | ||||
struct sockaddr *const sa | struct sockaddr *const sa | ||||
= (struct sockaddr *)msg->data; | = (struct sockaddr *)msg->data; | ||||
▲ Show 20 Lines • Show All 321 Lines • ▼ Show 20 Lines | if (!(so->so_state & SS_ISCONNECTING)) { | ||||
NG_SEND_MSG_ID(error, node, | NG_SEND_MSG_ID(error, node, | ||||
response, priv->response_addr, 0); | response, priv->response_addr, 0); | ||||
} | } | ||||
priv->flags &= ~KSF_CONNECTING; | priv->flags &= ~KSF_CONNECTING; | ||||
} | } | ||||
} | } | ||||
/* Check whether a pending accept operation has completed */ | /* Check whether a pending accept operation has completed */ | ||||
if (priv->flags & KSF_ACCEPTING) { | if (priv->flags & KSF_ACCEPTING) | ||||
error = ng_ksocket_check_accept(priv); | (void )ng_ksocket_accept(priv); | ||||
if (error != EWOULDBLOCK) | |||||
priv->flags &= ~KSF_ACCEPTING; | |||||
if (error == 0) | |||||
ng_ksocket_finish_accept(priv); | |||||
} | |||||
/* | /* | ||||
* If we don't have a hook, we must handle data events later. When | * If we don't have a hook, we must handle data events later. When | ||||
* the hook gets created and is connected, this upcall function | * the hook gets created and is connected, this upcall function | ||||
* will be called again. | * will be called again. | ||||
*/ | */ | ||||
if (priv->hook == NULL) | if (priv->hook == NULL) | ||||
return; | return; | ||||
▲ Show 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | if (so->so_rcv.sb_state & SBS_CANTRCVMORE && | ||||
m = m_gethdr(M_NOWAIT, MT_DATA); | m = m_gethdr(M_NOWAIT, MT_DATA); | ||||
if (m != NULL) | if (m != NULL) | ||||
NG_SEND_DATA_ONLY(error, priv->hook, m); | NG_SEND_DATA_ONLY(error, priv->hook, m); | ||||
priv->flags |= KSF_EOFSEEN; | priv->flags |= KSF_EOFSEEN; | ||||
} | } | ||||
} | } | ||||
/* | |||||
* Check for a completed incoming connection and return 0 if one is found. | |||||
* Otherwise return the appropriate error code. | |||||
*/ | |||||
static int | static int | ||||
ng_ksocket_check_accept(priv_p priv) | ng_ksocket_accept(priv_p priv) | ||||
{ | { | ||||
struct socket *const head = priv->so; | struct socket *const head = priv->so; | ||||
int error; | |||||
if ((error = head->so_error) != 0) { | |||||
head->so_error = 0; | |||||
return error; | |||||
} | |||||
/* Unlocked read. */ | |||||
if (TAILQ_EMPTY(&head->so_comp)) { | |||||
if (head->so_rcv.sb_state & SBS_CANTRCVMORE) | |||||
return ECONNABORTED; | |||||
return EWOULDBLOCK; | |||||
} | |||||
return 0; | |||||
} | |||||
/* | |||||
* Handle the first completed incoming connection, assumed to be already | |||||
* on the socket's so_comp queue. | |||||
*/ | |||||
static void | |||||
ng_ksocket_finish_accept(priv_p priv) | |||||
{ | |||||
struct socket *const head = priv->so; | |||||
struct socket *so; | struct socket *so; | ||||
struct sockaddr *sa = NULL; | struct sockaddr *sa = NULL; | ||||
struct ng_mesg *resp; | struct ng_mesg *resp; | ||||
struct ng_ksocket_accept *resp_data; | struct ng_ksocket_accept *resp_data; | ||||
node_p node; | node_p node; | ||||
priv_p priv2; | priv_p priv2; | ||||
int len; | int len; | ||||
int error; | int error; | ||||
ACCEPT_LOCK(); | SOLISTEN_LOCK(head); | ||||
so = TAILQ_FIRST(&head->so_comp); | error = solisten_dequeue(head, &so, SOCK_NONBLOCK); | ||||
if (so == NULL) { /* Should never happen */ | if (error == EWOULDBLOCK) { | ||||
ACCEPT_UNLOCK(); | priv->flags |= KSF_ACCEPTING; | ||||
return; | return (error); | ||||
} | } | ||||
TAILQ_REMOVE(&head->so_comp, so, so_list); | priv->flags &= ~KSF_ACCEPTING; | ||||
head->so_qlen--; | if (error) | ||||
so->so_qstate &= ~SQ_COMP; | return (error); | ||||
so->so_head = NULL; | |||||
SOCK_LOCK(so); | |||||
soref(so); | |||||
so->so_state |= SS_NBIO; | |||||
SOCK_UNLOCK(so); | |||||
ACCEPT_UNLOCK(); | |||||
/* XXX KNOTE_UNLOCKED(&head->so_rcv.sb_sel.si_note, 0); */ | |||||
soaccept(so, &sa); | soaccept(so, &sa); | ||||
len = OFFSETOF(struct ng_ksocket_accept, addr); | len = OFFSETOF(struct ng_ksocket_accept, addr); | ||||
if (sa != NULL) | if (sa != NULL) | ||||
len += sa->sa_len; | len += sa->sa_len; | ||||
NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len, | NG_MKMESSAGE(resp, NGM_KSOCKET_COOKIE, NGM_KSOCKET_ACCEPT, len, | ||||
M_NOWAIT); | M_NOWAIT); | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | ng_ksocket_accept(priv_p priv) | ||||
resp_data->nodeid = NG_NODE_ID(node); | resp_data->nodeid = NG_NODE_ID(node); | ||||
if (sa != NULL) | if (sa != NULL) | ||||
bcopy(sa, &resp_data->addr, sa->sa_len); | bcopy(sa, &resp_data->addr, sa->sa_len); | ||||
NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0); | NG_SEND_MSG_ID(error, node, resp, priv->response_addr, 0); | ||||
out: | out: | ||||
if (sa != NULL) | if (sa != NULL) | ||||
free(sa, M_SONAME); | free(sa, M_SONAME); | ||||
return (0); | |||||
} | } | ||||
/* | /* | ||||
* Parse out either an integer value or an alias. | * Parse out either an integer value or an alias. | ||||
*/ | */ | ||||
static int | static int | ||||
ng_ksocket_parse(const struct ng_ksocket_alias *aliases, | ng_ksocket_parse(const struct ng_ksocket_alias *aliases, | ||||
const char *s, int family) | const char *s, int family) | ||||
Show All 18 Lines |