main.c 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #include <unistd.h>
  2. #include <err.h>
  3. #include <errno.h>
  4. #include <pthread.h>
  5. #include <pthread_np.h>
  6. #include <sys/types.h>
  7. #include <sys/mman.h>
  8. #include <sys/socket.h>
  9. #include <netinet/in.h> /* bind */
  10. #include <fcntl.h> // O_xxxx
  11. #include <signal.h>
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h> //bzero
  15. const char* pathname="/rats";
  16. static void *udpController(void *dummy)
  17. {
  18. /*
  19. *
  20. * block SIGINT
  21. * to make sure this signal
  22. * will be handled by the main thread
  23. * because this is this thread's way to terminate
  24. * the process
  25. *
  26. */
  27. sigset_t sigmask;
  28. sigemptyset(&sigmask);
  29. sigaddset(&sigmask,SIGINT);
  30. if(sigprocmask(SIG_BLOCK,&sigmask,NULL))
  31. perror("sigprocmask");
  32. /*
  33. *
  34. * create share memory segment
  35. *
  36. */
  37. // may use SHM_ANON running FreeBSD while called by the same process
  38. int fd=shm_open(pathname,O_RDWR,0600);
  39. if (fd < 0){
  40. warn("%s: shm_open", __func__);
  41. pthread_exit(NULL);
  42. }
  43. if (ftruncate(fd, getpagesize()) < 0){
  44. warn("%s: ftruncate", __func__);
  45. pthread_exit(NULL);
  46. }
  47. /*
  48. *
  49. * open an UDP socket
  50. *
  51. */
  52. int s=socket(PF_INET,SOCK_DGRAM,0);
  53. if(-1==s){
  54. warn("socket");
  55. pthread_exit(NULL);
  56. }
  57. /*
  58. * Socket address, internet style.
  59. */
  60. struct sockaddr_in sa;
  61. bzero(&sa,sizeof sa);
  62. sa.sin_len=sizeof sa;
  63. sa.sin_family=AF_INET;
  64. sa.sin_port=htons(5514);
  65. //sa.sin_addr.s_addr = htonl((((((127 << 8) | 0) << 8) | 0) << 8) | 1);
  66. sa.sin_addr.s_addr = INADDR_ANY;
  67. uint32_t cursor;
  68. if(!bind(s,(struct sockaddr*)&sa,sizeof sa)){
  69. for(;;){
  70. char buffer[getpagesize()];
  71. int n=read(s,&buffer[4],getpagesize()-4);
  72. if(n==-1){
  73. break;
  74. }
  75. if(n>0){
  76. if(!bcmp((char*)&buffer[4],"quit",4)){
  77. printf("kill request\n");
  78. /* bye */
  79. kill(getpid(),SIGINT);
  80. break;
  81. }
  82. /* prepend length into the buffer */
  83. cursor=n+4;
  84. buffer[0]= (n>> 24);
  85. buffer[1]= (n>> 16);
  86. buffer[2]= (n>> 8);
  87. buffer[3]= (n);
  88. ssize_t len = pwrite(fd, buffer, cursor, 0);
  89. if(len<0){
  90. warn("%s: pwrite failure", __func__);
  91. }
  92. if(len!=cursor){
  93. warn("%zu vs %du, %s: pwrite length mismatch",len,cursor, __func__);
  94. }
  95. }
  96. }
  97. }else
  98. warn("bind failure");
  99. close (s);
  100. pthread_exit(NULL);
  101. }
  102. static void showmem()
  103. {
  104. int fd = shm_open(pathname, O_RDONLY, 0600);
  105. if (fd < 0) {
  106. warn("%s: shm_open", __func__);
  107. return;
  108. }
  109. /* extract length */
  110. uint8_t curbuf[4];
  111. ssize_t len=pread(fd, &curbuf, 4, 0);
  112. if (len == 4) {
  113. uint32_t l = (uint32_t)curbuf[0] << 24 |
  114. (uint32_t)curbuf[1] << 16 |
  115. (uint32_t)curbuf[2] << 8 |
  116. (uint32_t)curbuf[3];
  117. if (l > 0) {
  118. uint8_t* buf = malloc(l);
  119. if (buf) {
  120. /* data */
  121. ssize_t total=pread(fd,buf,l,4);
  122. printf("%zu:\t %s",total,buf);
  123. free(buf);
  124. } else {
  125. warn("malloc");
  126. }
  127. }
  128. } else {
  129. printf("nothing.\n");
  130. }
  131. }
  132. void
  133. sigHandler(int signo, siginfo_t *si, void * /* ucontext_t */ uap)
  134. {
  135. switch (signo) {
  136. case SIGINFO:
  137. printf("no need to panic.\n");
  138. __attribute__((fallthrough));
  139. case SIGALRM:
  140. showmem();
  141. break;
  142. default:
  143. printf("sig:%d received.", signo);
  144. break;
  145. }
  146. }
  147. int main(int argc, char* argv[])
  148. {
  149. timer_t timerid;
  150. int fd = shm_open(pathname, O_CREAT | O_RDWR, 0600);
  151. if (fd < 0)
  152. err(EPERM, "%s: shm_open", __func__);
  153. if (ftruncate(fd, getpagesize()) < 0)
  154. err(EIO, "%s: ftruncate", __func__);
  155. pthread_t pidudp;
  156. pthread_create(&pidudp, NULL, &udpController, NULL);
  157. /* signal */
  158. struct sigaction sa;
  159. sa.sa_handler = NULL;
  160. sa.sa_sigaction = &sigHandler;
  161. sa.sa_flags = SA_SIGINFO;
  162. sigemptyset(&sa.sa_mask);
  163. // Block every signal during the handler
  164. sigfillset(&sa.sa_mask);
  165. if (sigaction(SIGINFO, &sa, NULL)) {
  166. warn("SIGNFO not caught.");
  167. }
  168. if (sigaction(SIGALRM, &sa, NULL)) {
  169. err(2, "sigaction:ALARM");
  170. }
  171. /* timer */
  172. if (timer_create(CLOCK_REALTIME, NULL, &timerid)) {
  173. err(2,"timer_create failed.");
  174. }
  175. /* 3 -> TIMER_MAX stored into timerid->oshandle */
  176. printf("Timer #%d now created at address %p.\n", timer_oshandle_np(timerid), timerid);
  177. /* Set values and start timer */
  178. struct itimerspec its;
  179. its.it_interval.tv_sec = 2;
  180. its.it_interval.tv_nsec = 0;
  181. its.it_value.tv_sec = its.it_interval.tv_sec;
  182. its.it_value.tv_nsec = 0;
  183. if (timer_settime(timerid, 0, &its, NULL)) {
  184. warn("timer_settime failed.");
  185. }
  186. printf("waiting...\n");
  187. sigset_t sigmask;
  188. sigemptyset(&sigmask);
  189. sigaddset(&sigmask,SIGINT);
  190. sigprocmask(SIG_BLOCK,&sigmask,NULL);
  191. int sigpending;
  192. if(sigwait(&sigmask,&sigpending))
  193. warn("sigwait failure.\n");
  194. //brutal thread killing, I know it s bad. but I 'm punk btw.
  195. printf("bye\n");
  196. timer_delete(timerid);
  197. struct timespec t;
  198. if (!clock_gettime(CLOCK_REALTIME, &t)) {
  199. t.tv_sec += 5;
  200. if (pthread_timedjoin_np(pidudp, NULL, &t)) {
  201. pthread_cancel(pidudp);
  202. }
  203. } else {
  204. warn("clock_gettime");
  205. }
  206. // required until SHM_ANON is used, or shm remains (persistent until reboot)
  207. shm_unlink(pathname);
  208. }