#include #include #include #include #include #include #include #include #include /* bind */ #include // O_xxxx #include #include #include #include //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); }