|
@@ -0,0 +1,239 @@
|
|
|
|
|
+#include <unistd.h>
|
|
|
|
|
+#include <err.h>
|
|
|
|
|
+#include <errno.h>
|
|
|
|
|
+#include <pthread.h>
|
|
|
|
|
+#include <pthread_np.h>
|
|
|
|
|
+#include <sys/types.h>
|
|
|
|
|
+#include <sys/mman.h>
|
|
|
|
|
+#include <sys/socket.h>
|
|
|
|
|
+#include <netinet/in.h> /* bind */
|
|
|
|
|
+#include <fcntl.h> // O_xxxx
|
|
|
|
|
+#include <signal.h>
|
|
|
|
|
+#include <stdio.h>
|
|
|
|
|
+#include <stdlib.h>
|
|
|
|
|
+#include <string.h> //bzero
|
|
|
|
|
+
|
|
|
|
|
+const char* pathname="/rats";
|
|
|
|
|
+
|
|
|
|
|
+static void *udpController(void *dummy)
|
|
|
|
|
+{
|
|
|
|
|
+ /*
|
|
|
|
|
+ *
|
|
|
|
|
+ * block SIGINT
|
|
|
|
|
+ * to make sure this signal
|
|
|
|
|
+ * will be handled by the main thread
|
|
|
|
|
+ * because this is this thread's way to terminate
|
|
|
|
|
+ * the process
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+ sigset_t sigmask;
|
|
|
|
|
+ sigemptyset(&sigmask);
|
|
|
|
|
+ sigaddset(&sigmask,SIGINT);
|
|
|
|
|
+ if(sigprocmask(SIG_BLOCK,&sigmask,NULL))
|
|
|
|
|
+ perror("sigprocmask");
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ *
|
|
|
|
|
+ * create share memory segment
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+ // may use SHM_ANON running FreeBSD while called by the same process
|
|
|
|
|
+ int fd=shm_open(pathname,O_RDWR,0600);
|
|
|
|
|
+ if (fd < 0){
|
|
|
|
|
+ warn("%s: shm_open", __func__);
|
|
|
|
|
+ pthread_exit(NULL);
|
|
|
|
|
+ }
|
|
|
|
|
+ if (ftruncate(fd, getpagesize()) < 0){
|
|
|
|
|
+ warn("%s: ftruncate", __func__);
|
|
|
|
|
+ pthread_exit(NULL);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ *
|
|
|
|
|
+ * open an UDP socket
|
|
|
|
|
+ *
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+ int s=socket(PF_INET,SOCK_DGRAM,0);
|
|
|
|
|
+ if(-1==s){
|
|
|
|
|
+ warn("socket");
|
|
|
|
|
+ pthread_exit(NULL);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * Socket address, internet style.
|
|
|
|
|
+ */
|
|
|
|
|
+
|
|
|
|
|
+ struct sockaddr_in sa;
|
|
|
|
|
+ bzero(&sa,sizeof sa);
|
|
|
|
|
+ sa.sin_len=sizeof sa;
|
|
|
|
|
+ sa.sin_family=AF_INET;
|
|
|
|
|
+ sa.sin_port=htons(5514);
|
|
|
|
|
+ //sa.sin_addr.s_addr = htonl((((((127 << 8) | 0) << 8) | 0) << 8) | 1);
|
|
|
|
|
+ sa.sin_addr.s_addr = INADDR_ANY;
|
|
|
|
|
+ uint32_t cursor;
|
|
|
|
|
+ if(!bind(s,(struct sockaddr*)&sa,sizeof sa)){
|
|
|
|
|
+
|
|
|
|
|
+ for(;;){
|
|
|
|
|
+ char buffer[getpagesize()];
|
|
|
|
|
+ int n=read(s,&buffer[4],getpagesize()-4);
|
|
|
|
|
+ if(n==-1){
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ if(n>0){
|
|
|
|
|
+ if(!bcmp((char*)&buffer[4],"quit",4)){
|
|
|
|
|
+ printf("kill request\n");
|
|
|
|
|
+ /* bye */
|
|
|
|
|
+ kill(getpid(),SIGINT);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* prepend length into the buffer */
|
|
|
|
|
+ cursor=n+4;
|
|
|
|
|
+ buffer[0]= (n>> 24);
|
|
|
|
|
+ buffer[1]= (n>> 16);
|
|
|
|
|
+ buffer[2]= (n>> 8);
|
|
|
|
|
+ buffer[3]= (n);
|
|
|
|
|
+
|
|
|
|
|
+ ssize_t len = pwrite(fd, buffer, cursor, 0);
|
|
|
|
|
+
|
|
|
|
|
+ if(len<0){
|
|
|
|
|
+ warn("%s: pwrite failure", __func__);
|
|
|
|
|
+ }
|
|
|
|
|
+ if(len!=cursor){
|
|
|
|
|
+ warn("%zu vs %du, %s: pwrite length mismatch",len,cursor, __func__);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }else
|
|
|
|
|
+ warn("bind failure");
|
|
|
|
|
+
|
|
|
|
|
+ close (s);
|
|
|
|
|
+ pthread_exit(NULL);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void showmem()
|
|
|
|
|
+{
|
|
|
|
|
+ int fd = shm_open(pathname, O_RDONLY, 0600);
|
|
|
|
|
+
|
|
|
|
|
+ if (fd < 0) {
|
|
|
|
|
+ warn("%s: shm_open", __func__);
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* extract length */
|
|
|
|
|
+ uint8_t curbuf[4];
|
|
|
|
|
+ ssize_t len=pread(fd, &curbuf, 4, 0);
|
|
|
|
|
+ if (len == 4) {
|
|
|
|
|
+ uint32_t l = (uint32_t)curbuf[0] << 24 |
|
|
|
|
|
+ (uint32_t)curbuf[1] << 16 |
|
|
|
|
|
+ (uint32_t)curbuf[2] << 8 |
|
|
|
|
|
+ (uint32_t)curbuf[3];
|
|
|
|
|
+ if (l > 0) {
|
|
|
|
|
+ uint8_t* buf = malloc(l);
|
|
|
|
|
+ if (buf) {
|
|
|
|
|
+ /* data */
|
|
|
|
|
+ ssize_t total=pread(fd,buf,l,4);
|
|
|
|
|
+ printf("%zu:\t %s",total,buf);
|
|
|
|
|
+ free(buf);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ warn("malloc");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ printf("nothing.\n");
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+void
|
|
|
|
|
+sigHandler(int signo, siginfo_t *si, void * /* ucontext_t */ uap)
|
|
|
|
|
+{
|
|
|
|
|
+ switch (signo) {
|
|
|
|
|
+ case SIGINFO:
|
|
|
|
|
+ printf("no need to panic.\n");
|
|
|
|
|
+ __attribute__((fallthrough));
|
|
|
|
|
+ case SIGALRM:
|
|
|
|
|
+ showmem();
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ printf("sig:%d received.", signo);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+int main(int argc, char* argv[])
|
|
|
|
|
+{
|
|
|
|
|
+ timer_t timerid;
|
|
|
|
|
+ int fd = shm_open(pathname, O_CREAT | O_RDWR, 0600);
|
|
|
|
|
+
|
|
|
|
|
+ if (fd < 0)
|
|
|
|
|
+ err(EPERM, "%s: shm_open", __func__);
|
|
|
|
|
+ if (ftruncate(fd, getpagesize()) < 0)
|
|
|
|
|
+ err(EIO, "%s: ftruncate", __func__);
|
|
|
|
|
+
|
|
|
|
|
+ pthread_t pidudp;
|
|
|
|
|
+ pthread_create(&pidudp, NULL, &udpController, NULL);
|
|
|
|
|
+ /* signal */
|
|
|
|
|
+ struct sigaction sa;
|
|
|
|
|
+ sa.sa_handler = NULL;
|
|
|
|
|
+ sa.sa_sigaction = &sigHandler;
|
|
|
|
|
+ sa.sa_flags = SA_SIGINFO;
|
|
|
|
|
+ sigemptyset(&sa.sa_mask);
|
|
|
|
|
+ // Block every signal during the handler
|
|
|
|
|
+ sigfillset(&sa.sa_mask);
|
|
|
|
|
+ if (sigaction(SIGINFO, &sa, NULL)) {
|
|
|
|
|
+ warn("SIGNFO not caught.");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (sigaction(SIGALRM, &sa, NULL)) {
|
|
|
|
|
+ err(2, "sigaction:ALARM");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /* timer */
|
|
|
|
|
+ if (timer_create(CLOCK_REALTIME, NULL, &timerid)) {
|
|
|
|
|
+ err(2,"timer_create failed.");
|
|
|
|
|
+ }
|
|
|
|
|
+ /* 3 -> TIMER_MAX stored into timerid->oshandle */
|
|
|
|
|
+ printf("Timer #%d now created at address %p.\n", timer_oshandle_np(timerid), timerid);
|
|
|
|
|
+ /* Set values and start timer */
|
|
|
|
|
+ struct itimerspec its;
|
|
|
|
|
+ its.it_interval.tv_sec = 2;
|
|
|
|
|
+ its.it_interval.tv_nsec = 0;
|
|
|
|
|
+ its.it_value.tv_sec = its.it_interval.tv_sec;
|
|
|
|
|
+ its.it_value.tv_nsec = 0;
|
|
|
|
|
+
|
|
|
|
|
+ if (timer_settime(timerid, 0, &its, NULL)) {
|
|
|
|
|
+ warn("timer_settime failed.");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ printf("waiting...\n");
|
|
|
|
|
+ sigset_t sigmask;
|
|
|
|
|
+ sigemptyset(&sigmask);
|
|
|
|
|
+ sigaddset(&sigmask,SIGINT);
|
|
|
|
|
+ sigprocmask(SIG_BLOCK,&sigmask,NULL);
|
|
|
|
|
+
|
|
|
|
|
+ int sigpending;
|
|
|
|
|
+ if(sigwait(&sigmask,&sigpending))
|
|
|
|
|
+ warn("sigwait failure.\n");
|
|
|
|
|
+ //brutal thread killing, I know it s bad. but I 'm punk btw.
|
|
|
|
|
+ printf("bye\n");
|
|
|
|
|
+ timer_delete(timerid);
|
|
|
|
|
+ struct timespec t;
|
|
|
|
|
+ if (!clock_gettime(CLOCK_REALTIME, &t)) {
|
|
|
|
|
+ t.tv_sec += 5;
|
|
|
|
|
+ if (pthread_timedjoin_np(pidudp, NULL, &t)) {
|
|
|
|
|
+ pthread_cancel(pidudp);
|
|
|
|
|
+ }
|
|
|
|
|
+ } else {
|
|
|
|
|
+ warn("clock_gettime");
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // required until SHM_ANON is used, or shm remains (persistent until reboot)
|
|
|
|
|
+ shm_unlink(pathname);
|
|
|
|
|
+}
|