Register a secure event
#include <sys/neutrino.h> int MsgRegisterEvent( struct sigevent *event, int coid ); int MsgRegisterEvent_r( struct sigevent *event, int coid );
The coid argument can contain any type of connection ID, including a side channel ID, message queue descriptor, socket descriptor, or file descriptor.
If you want to receive events from the process manager, you can pass in SYSMGR_COID for this argument.
libc
Use the -l c option to qcc to link against this library. This library is usually included automatically.
The MsgRegisterEvent() and MsgRegisterEvent_r() kernel calls register the given sigevent as a secure event. These functions are identical except in the way they indicate errors. See the Returns section for details.
MsgRegisterEvent() registers the given sigevent with the kernel and converts it into a handle that you can use in any API that passes an event. When the server calls MsgDeliverEvent() with a handle event, the kernel looks up the handle. If the handle exists and the server is allowed to deliver it, the kernel delivers the registered event. For more information about secure events, see Events in the Interprocess Communication (IPC) chapter of the System Architecture guide.
You can use MsgUnregisterEvent() to unregister the secure event.
Blocking states
None.
The only difference between these functions is the way they indicate errors:
In this example, the parent process acts as the server, and the child acts as the client.
#include <stdio.h> #include <stdint.h> #include <unistd.h> #include <signal.h> #include <errno.h> #include <sys/neutrino.h> #include <sys/wait.h> struct message_s { uint16_t type; uint16_t subtype; struct sigevent event; struct sigevent updateable; struct sigevent forbidden; }; static int child(int chid) { // Mask SIGUSR1 and SIGUSR2. sigset_t sigset; siginfo_t siginfo; sigemptyset(&sigset); sigaddset(&sigset, SIGUSR1); sigaddset(&sigset, SIGUSR2); if (sigprocmask(SIG_BLOCK, &sigset, NULL) < 0) { perror("sigprocmask"); return 1; } // Attach to the server, indicating that we don't want unregistered events. int coid = ConnectAttach(0, getppid(), chid, _NTO_SIDE_CHANNEL, _NTO_COF_REG_EVENTS); if (coid < 0) { perror("ConnectAttach"); return 1; } // Register three events: // 1. Non-updateable, on a connection to the parent server // 2. Updateable, on a connection to the parent server // 3. On a connection to procnto struct message_s msg = { .type = 1 }; // First event. SIGEV_SIGNAL_VALUE_INIT(&msg.event, SIGUSR1, 13); if (MsgRegisterEvent(&msg.event, coid) < 0) { perror("MsgRegisterEvent(&msg.event)"); return 1; } // Second event. SIGEV_SIGNAL_VALUE_INIT(&msg.updateable, SIGUSR2, 34); SIGEV_MAKE_UPDATEABLE(&msg.updateable); if (MsgRegisterEvent(&msg.updateable, coid) < 0) { perror("MsgRegisterEvent(&msg.updateable)"); return 1; } // Third event. SIGEV_SIGNAL_VALUE_INIT(&msg.forbidden, SIGUSR2, 34); if (MsgRegisterEvent(&msg.forbidden, SYSMGR_COID) < 0) { perror("MsgRegisterEvent(&msg.forbidden)"); return 1; } // Send the server a message that includes the sigevents. if (MsgSend(coid, &msg, sizeof(msg), NULL, 0) < 0) { perror("MsgSend"); return 1; } // Wait for event delivery. int i = 0; for (i = 0; i < 2; i++) { printf("Waiting for SIGUSR1/SIGUSR2\n"); if (sigwaitinfo(&sigset, &siginfo) < 0) { perror("sigwaitinfo"); return 1; } switch (siginfo.si_signo) { case SIGUSR1: printf("Received SIGUSR1 with value %d\n", siginfo.si_value.sival_int); if (siginfo.si_value.sival_int != 13) { fprintf(stderr, "SIGUSR1: Expected value 13, got %d\n", siginfo.si_value.sival_int); return 1; } break; case SIGUSR2: printf("Received SIGUSR2 with value %d\n", siginfo.si_value.sival_int); if (siginfo.si_value.sival_int != 57) { fprintf(stderr, "SIGUSR1: Expected value 57, got %d\n", siginfo.si_value.sival_int); return 1; } break; default: fprintf(stderr, "Unexpected signal %d\n", siginfo.si_signo); return 1; } } return 0; } int main(int argc, char **argv) { // Create a channel. int chid = ChannelCreate(0); if (chid < 0) { perror("ChannelCreate"); return 1; } // Create a child process. pid_t pid = fork(); if (pid < 0) { perror("fork"); return 1; } if (pid == 0) { return child(chid); } // Handle messages from the child. int kill_child = 1; for (;;) { struct message_s msg; int rcvid; rcvid = MsgReceive(chid, &msg, sizeof(msg), NULL); if (rcvid < 0) { perror("MsgReceive"); break; } if (rcvid == 0) { continue; } printf("Received message type %d\n", msg.type); MsgReply(rcvid, 0, NULL, 0); kill_child = 0; // Try a handle for an event that this server isn't allowed to send. if ((MsgDeliverEvent(rcvid, &msg.forbidden) != -1) || (errno != EACCES)) { perror("MsgDeliverEvent(forbidden)"); break; } // Try an unregistered event. It shouldn't be delivered. struct sigevent ev; SIGEV_SIGNAL_INIT(&ev, SIGUSR1); if ((MsgDeliverEvent(rcvid, &ev) != -1) || (errno != EACCES)) { perror("MsgDeliverEvent(unregistered)"); break; } // Try a legitimate handle that doesn't have an updateable value. // The client should get the original value that it registered. msg.event.sigev_value.sival_int = 57; if (MsgDeliverEvent(rcvid, &msg.event) < 0) { perror("MsgDeliverEvent"); break; } // Try a legitimate handle that has an updateable value. msg.updateable.sigev_value.sival_int = 57; if (MsgDeliverEvent(rcvid, &msg.updateable) < 0) { perror("MsgDeliverEvent"); break; } break; } if (kill_child) { kill(pid, SIGKILL); } int status; pid_t wpid = waitpid(pid, &status, 0); if (wpid != pid) { perror("waitpid"); return 1; } printf("Child exited with status %d\n", WEXITSTATUS(status)); return 0; }
Safety: | |
---|---|
Cancellation point | No |
Interrupt handler | No |
Signal handler | Yes |
Thread | Yes |