/* datasink service has no per channel state so we can *justattachhandlerstructdirectlytochannelhandle
*/ staticstruct tipc_event_handler _datasink_chan_handler = {
.proc = datasink_handle_chan,
.priv = NULL,
};
staticvoid _destroy_service(struct tipc_srv_state* state) { if (!state) {
TLOGI("non-null state expected\n"); return;
}
/* free state if any */ if (state->priv) {
free(state->priv);
state->priv = NULL;
}
/* close port */ if (state->port != INVALID_IPC_HANDLE) { int rc = close(state->port); if (rc != NO_ERROR) {
TLOGI("Failed (%d) to close port %d\n", rc, state->port);
}
state->port = INVALID_IPC_HANDLE;
}
/* create port */ int rc = port_create(srv->name, srv->msg_num, srv->msg_size,
srv->port_flags); if (rc < 0) {
TLOGI("Failed (%d) to create port\n", rc); return rc;
}
/* setup port state */
state->port = (handle_t)rc;
state->handler.proc = srv->port_handler;
state->handler.priv = state;
state->service = srv;
state->priv = NULL;
if (srv->port_state_size) { /* allocate port state */
state->priv = calloc(1, srv->port_state_size); if (!state->priv) {
rc = ERR_NO_MEMORY; goto err_calloc;
}
}
/* attach handler to port handle */
rc = set_cookie(state->port, &state->handler); if (rc < 0) {
TLOGI("Failed (%d) to set cookie on port %d\n", rc, state->port); goto err_set_cookie;
}
for (unsignedint i = 0; i < countof(_services); i++) { int rc = _create_service(&_services[i], &_srv_states[i]); if (rc < 0) {
TLOGI("Failed (%d) to create service %s\n", rc, _services[i].name); return rc;
}
}
return0;
}
/* *Handlecommonporterrors
*/ staticbool handle_port_errors(const uevent_t* ev) { if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
(ev->event & IPC_HANDLE_POLL_HUP) ||
(ev->event & IPC_HANDLE_POLL_MSG) ||
(ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) { /* should never happen with port handles */
TLOGI("error event (0x%x) for port (%d)\n", ev->event, ev->handle);
/* recreate service */
restart_service(get_srv_state(ev)); returntrue;
}
returnfalse;
}
/****************************** connect test service *********************/
/* *Localwrapperontopofasyncconnectthatprovides *synchronosconnectwithtimeout.
*/ int sync_connect(constchar* path, unsignedint timeout) { int rc;
uevent_t evt;
handle_t chan;
rc = connect(path, IPC_CONNECT_ASYNC | IPC_CONNECT_WAIT_FOR_PORT); if (rc >= 0) {
chan = (handle_t)rc;
rc = wait(chan, &evt, timeout); if (rc == 0) {
rc = ERR_BAD_STATE; if (evt.handle == chan) { if (evt.event & IPC_HANDLE_POLL_READY) return chan;
if (ev->event & IPC_HANDLE_POLL_READY) { char path[MAX_PORT_PATH_LEN];
/* accept incomming connection and close it */ int rc = accept(ev->handle, &peer_uuid); if (rc < 0 && rc != ERR_CHANNEL_CLOSED) {
TLOGI("accept failed (%d)\n", rc); return;
} if (rc >= 0) {
close((handle_t)rc);
}
/* but then issue a series of connect requests */ for (unsignedint i = FIRST_FREE_HANDLE; i < MAX_USER_HANDLES; i++) {
sprintf(path, "%s.port.accept%d", SRV_PATH_BASE, i);
rc = sync_connect(path, 1000);
close((handle_t)rc);
}
}
}
if (ev->event & IPC_HANDLE_POLL_READY) { /* new connection request, bump counter */
st->conn_cnt++;
/* accept it */ int rc = accept(ev->handle, &peer_uuid); if (rc < 0) {
TLOGI("accept failed (%d)\n", rc); return;
}
handle_t chan = (handle_t)rc;
if (st->conn_cnt & 1) { /* sleep a bit */
trusty_nanosleep(0, 0, 100 * MSEC);
} /* and close it */
rc = close(chan); if (rc != NO_ERROR) {
TLOGI("Failed (%d) to close chan %d\n", rc, chan);
}
}
}
staticvoid closer2_handle_port(const uevent_t* ev) { struct closer2_state* st = get_srv_state(ev)->priv;
if (handle_port_errors(ev)) return;
if (ev->event & IPC_HANDLE_POLL_READY) { /* new connection request, bump counter */
st->conn_cnt++; if (st->conn_cnt & 1) { /* sleep a bit */
trusty_nanosleep(0, 0, 100 * MSEC);
}
if (ev->event & IPC_HANDLE_POLL_READY) { /* accept connection */ int rc = accept(ev->handle, &peer_uuid); if (rc < 0) {
TLOGI("accept failed (%d)\n", rc); return;
} /* add it to connection pool */
st->chans[st->chan_cnt++] = (handle_t)rc;
/* attach datasink service handler just in case */
set_cookie((handle_t)rc, &_datasink_chan_handler);
/* when max number of connection reached */ if (st->chan_cnt == countof(st->chans)) { /* wait a bit */
trusty_nanosleep(0, 0, 100 * MSEC);
/* and close them all */ for (unsignedint i = 0; i < st->chan_cnt; i++)
close(st->chans[i]);
st->chan_cnt = 0;
} return;
}
}
/****************************** datasync service **************************/
staticint datasink_handle_msg(const uevent_t* ev) { int rc;
ipc_msg_info_t inf;
/* for all messages */ for (;;) { /* get message */
rc = get_msg(ev->handle, &inf); if (rc == ERR_NO_MSG) break; /* no new messages */
if (rc != NO_ERROR) {
TLOGI("failed (%d) to get_msg for chan (%d)\n", rc, ev->handle); return rc;
}
/* and retire it without actually reading */
rc = put_msg(ev->handle, inf.id); if (rc != NO_ERROR) {
TLOGI("failed (%d) to putt_msg for chan (%d)\n", rc, ev->handle); return rc;
}
}
return NO_ERROR;
}
/* *Datasinkservicechannelhandler
*/ staticvoid datasink_handle_chan(const uevent_t* ev) { if ((ev->event & IPC_HANDLE_POLL_ERROR) ||
(ev->event & IPC_HANDLE_POLL_SEND_UNBLOCKED)) { /* close it as it is in an error state */
TLOGI("error event (0x%x) for chan (%d)\n", ev->event, ev->handle);
close(ev->handle); return;
}
if (ev->event & IPC_HANDLE_POLL_MSG) { if (datasink_handle_msg(ev) != 0) {
close(ev->handle); return;
}
}
if (ev->event & IPC_HANDLE_POLL_HUP) { /* closed by peer */
close(ev->handle); return;
}
}
if (ev->event & IPC_HANDLE_POLL_READY) { /* incomming connection: accept it */ int rc = accept(ev->handle, &peer_uuid); if (rc < 0) {
TLOGI("failed (%d) to accept on port %d\n", rc, ev->handle); return;
}
handle_t chan = (handle_t)rc;
rc = set_cookie(chan, &_datasink_chan_handler); if (rc) {
TLOGI("failed (%d) to set_cookie on chan %d\n", rc, chan);
}
}
}
/****************************** echo service **************************/
staticint send_msg_wait(handle_t chan, ipc_msg_t* msg) { int rc;
uevent_t ev;
while (true) {
rc = send_msg(chan, msg);
if (rc != ERR_NOT_ENOUGH_BUFFER) { return rc;
}
while (true) {
rc = wait(chan, &ev, INFINITE_TIME); if (rc < 0) { return rc;
}
if (ev.event & IPC_HANDLE_POLL_HUP) { /* *Itispossiblethatev.event&IPC_HANDLE_POLL_MSGisalso *truewhichmeanstheclientsentamessageandhunguponus. *Thereisn'tanythingtheechoservercandowiththose,sowe *simplylogtheoccurrence.
*/ if (ev.event & IPC_HANDLE_POLL_MSG) {
TLOGW("Client sent a message and hung up;" " message discarded.\n");
}
return ERR_CHANNEL_CLOSED;
}
if (ev.event & IPC_HANDLE_POLL_SEND_UNBLOCKED) { break;
}
/* if ev.event & IPC_HANDLE_POLL_MSG is true, continue looping */
}
}
/* read msg content */
rc = read_msg(ev->handle, msg_info.id, 0, &msg); if (rc < 0) {
TLOGI("failed (%d) to read_msg for chan (%d)\n", rc, ev->handle); return rc;
}
/* update number of bytes received */
st->echo_msgs[msg_cnt].msg_len = (size_t)rc;
/* retire original message */
rc = put_msg(ev->handle, msg_info.id); if (rc != NO_ERROR) {
TLOGI("failed (%d) to put_msg for chan (%d)\n", rc, ev->handle); return rc;
}
msg_cnt++;
}
/* echo all messages received */ for (unsignedint i = 0; i < msg_cnt; i++) { /* prepare message structure for send */ struct iovec iov = {
.iov_base = (void*)st->echo_msgs[i].msg_buf,
.iov_len = st->echo_msgs[i].msg_len,
};
msg.iov = &iov;
msg.handles = st->echo_msgs[i].handles;
msg.num_handles = st->echo_msgs[i].handle_cnt;
/* and send it back */
rc = send_msg_wait(ev->handle, &msg);
/* close all received handles */ for (unsignedint j = 0; j < msg.num_handles; j++) {
close(st->echo_msgs[i].handles[j]);
}
if (rc < 0) {
TLOGI("failed (%d) to send_msg for chan (%d)\n", rc, ev->handle); return rc;
}
} return NO_ERROR;
}
/* *echoservicechannelhandler
*/ staticvoid echo_handle_chan(const uevent_t* ev) { if (ev->event & IPC_HANDLE_POLL_ERROR) { /* close it as it is in an error state */
TLOGI("error event (0x%x) for chan (%d)\n", ev->event, ev->handle); goto close_it;
}
if (ev->event & (IPC_HANDLE_POLL_MSG | IPC_HANDLE_POLL_SEND_UNBLOCKED)) { if (echo_handle_msg(ev) != 0) {
TLOGI("error event (0x%x) for chan (%d)\n", ev->event, ev->handle); goto close_it;
}
}
if (ev->event & IPC_HANDLE_POLL_HUP) { goto close_it;
}
if (ev->event & IPC_HANDLE_POLL_READY) {
handle_t chan;
/* incomming connection: accept it */ int rc = accept(ev->handle, &peer_uuid); if (rc < 0) {
TLOGI("failed (%d) to accept on port %d\n", rc, ev->handle); return;
}
chan = (handle_t)rc;
if (ev->event == IPC_HANDLE_POLL_NONE) { /* not really an event, do nothing */
TLOGI("got an empty event\n"); return;
}
if (ev->handle == INVALID_IPC_HANDLE) { /* not a valid handle */
TLOGI("got an event (0x%x) with invalid handle (%d)", ev->event,
ev->handle); return;
}
/* check if we have handler */ struct tipc_event_handler* handler = ev->cookie; if (handler && handler->proc) { /* invoke it */
handler->proc(ev); return;
}
/* no handler? close it */
TLOGI("no handler for event (0x%x) with handle %d\n", ev->event,
ev->handle);
close(ev->handle);
return;
}
/* *Mainentrypointofservicetask
*/ int main(void) { int rc;
uevent_t event;
/* Initialize service */
rc = init_services(); if (rc != NO_ERROR) {
TLOGI("Failed (%d) to init service", rc);
kill_services(); return -1;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.