Advertisement
Guest User

Untitled

a guest
Jan 18th, 2020
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 15.01 KB | None | 0 0
  1. #include <stdio.h>
  2. #include <errno.h>
  3. #include <libgen.h>
  4. #include <string.h>
  5. #include <limits.h>
  6. #include <unistd.h>
  7. #include <stdbool.h>
  8. #include <dirent.h>
  9. #include <sys/types.h>
  10. #include <sys/stat.h>
  11. #include <sys/msg.h>
  12. #include <sys/mman.h>
  13. #include <stdlib.h>
  14. #include <fcntl.h>
  15. #include <wait.h>
  16. #include <signal.h>
  17.  
  18. #define POSPRZATAJ() do{wait(&pids[2]);remove(SCIEZKA_KOLEJKI_1);}while(0)
  19. #define DEBUGPIRNTF
  20.  
  21. #define DLUGOSC_KOMUNIKATU 1024
  22. #define SCIEZKA_KOLEJKI_1 "/tmp/projekt_so2"
  23.  
  24. /* Sygnał, który kończy działanie programu. */
  25. #define S1 SIGUSR1
  26. /* Sygnał, który zatrzymuje komunikację procesów. */
  27. #define S2 SIGUSR2
  28. /* Sygnał, który wznawia komunikację procesów. */
  29. #define S3 SIGCONT
  30.  
  31. #define ILE_PROCESOW 3
  32.  
  33. // Typy wiadomosci (mtype)
  34. #define WIADOMOSC_OD_MASTERA 1
  35.  
  36. // Struktura dla wiadomości typu WIADOMOSC_ARGC
  37. struct msgcargbuf {
  38.     long    mtype;          /* typ komunikatu */
  39.     long komunikat;
  40. } msgCargs;
  41.  
  42.  
  43. // Struktura dla wiadomości typu WIADOMOSC_OD_*
  44. struct mymsgbuf {
  45.     long    mtype;          /* typ komunikatu */
  46.     short czyOstatni;       /* czy ostatni komunikat (0=nie cokolwiek innego tak) */
  47.     char    komunikat[DLUGOSC_KOMUNIKATU];      /* Właściwa przesyłana informacja */
  48. } msg;
  49.  
  50. /* Tablica przechowuje PIDy procesów */
  51. int *pids;
  52. /* Czy pierwszy sygnał ma zostać wysłany do wszystkich procesów czy odebraliśmy ten sygnał od innego
  53.  * procesu */
  54. short *czyPierwszySygnal;
  55. /* Jak wyżej tylko dla procesu 2. */
  56. short *czyDrugiSygnal;
  57. /* Jak wyżej tylko dla procesu 3. */
  58. short *czyTrzeciSygnal;
  59.  
  60. int open_queue( key_t keyval ) {
  61.     int     qid;
  62.  
  63.     if((qid = msgget( keyval, IPC_CREAT | 0660 )) == -1)
  64.         return(-1);
  65.  
  66.     return(qid);
  67. }
  68.  
  69. int send_message( int qid, struct mymsgbuf *qbuf ){
  70.     int result;
  71.     size_t length;
  72.  
  73.     /* lenght jest rozmiarem struktury minus sizeof(mtype) */
  74.     length = sizeof(struct mymsgbuf) - sizeof(long);
  75.  
  76.     if((result = msgsnd( qid, qbuf, length, 0)) == -1)
  77.         return(-1);
  78.  
  79.     return(result);
  80. }
  81.  
  82. // Z plików z poprzedniego zadania.
  83. int remove_queue( int qid ){
  84.     if( msgctl( qid, IPC_RMID, 0) == -1)
  85.         return(-1);
  86.  
  87.     return(0);
  88. }
  89.  
  90. int read_message( int qid, long type, struct mymsgbuf *qbuf ){
  91.     int     result, length;
  92.  
  93.     /* lenght jest rozmiarem struktury minus sizeof(mtype) */
  94.     length = sizeof(struct mymsgbuf) - sizeof(long);
  95.  
  96.     if((result = msgrcv( qid, qbuf, length, type,  0)) == -1)
  97.         return(-1);
  98.  
  99.     return(result);
  100. }
  101.  
  102. /* Odczytuje komunikat i obsługuje błędy. */
  103. void odczytajKomunikat( int qid, long type, struct mymsgbuf *qbuf )
  104. {
  105.  
  106.     /* Wywołanie syscall może być przerwane przez sygnał ale nie chcę blokować sygnałów w tym miejscu,
  107.      * ponieważ w trybie interkatywnym program zatrzymuje się w tej tej funkcji w oczekiwaniu na dane co powodowałoby
  108.      * długie okresy kiedy sygnał nie może być obsłużony.
  109.      * To samo dotyczy sie każdego zapisu i odczytu z mechanizmów komunikacji międzyprocesowej i plików pomimo,
  110.      * że linux raczej nie przerywa na sygnale wywołań read/write. */
  111.     again:
  112.     errno = 0;
  113.     if( read_message(qid, type, qbuf ) == -1)
  114.     {
  115.         if(errno == EINTR)
  116.         {
  117.             goto again;
  118.         }
  119.         else {
  120.             perror("Odbieranie");
  121.             exit(2);
  122.         }
  123.     }
  124. }
  125.  
  126. /* Wysyła komunikat i obsługuje błędy. */
  127. void wyslijKomunikat(int qid, struct mymsgbuf *qbuf, long typ, char *wiadomosc, short czyOstatni)
  128. {
  129.     qbuf -> mtype= typ;        /* typ wiadomości musi być dodatni */
  130.     qbuf -> czyOstatni = czyOstatni;
  131.     strcpy(qbuf -> komunikat, wiadomosc);
  132.     /* Wysylamy */
  133.     again:
  134.     errno = 0;
  135.     if((send_message( qid, qbuf )) == -1) {
  136.         if(errno == EINTR)
  137.         {
  138.             goto again;
  139.         }
  140.         else
  141.         {
  142.             perror("Wysylanie");
  143.             exit(1);
  144.         }
  145.     }
  146. }
  147.  
  148. /* W tej funkcji zaimplemntowano działania procesu 1 */
  149. int proc1(key_t qid, int argc, char** argv);
  150. /* W tej funkcji zaimplemntowano działania procesu 2 */
  151. int proc2(key_t qid, char* sciezkaKolejki);
  152. /* W tej funkcji zaimplemntowano działania procesu 3 */
  153. int proc3(char* sciezkaKolejki);
  154.  
  155. void sigS1Handler(int signal)
  156. {
  157.     if(*czyPierwszySygnal)
  158.     {
  159.         *czyPierwszySygnal = 0;
  160.         for (int i = 0; i < ILE_PROCESOW; ++i)
  161.         {
  162.             if (pids[i] != getpid()) {
  163.                 kill(pids[i], S1);
  164.             }
  165.         }
  166.     }
  167.     exit(0);
  168. }
  169.  
  170. void sigS2Handler(int signal)
  171. {
  172.     if(*czyDrugiSygnal)
  173.     {
  174.         *czyDrugiSygnal = 0;
  175.         for (int i = 0; i < ILE_PROCESOW; ++i) {
  176.             if (pids[i] != getpid()) {
  177.                 kill(pids[i], S2);
  178.             }
  179.         }
  180.         *czyTrzeciSygnal = 1;
  181.     }
  182.     sigset_t mask;
  183.     sigfillset (&mask);
  184.     sigdelset(&mask, S1);
  185.     sigdelset(&mask, S2);
  186.     sigdelset(&mask, S3);
  187.  
  188.     /* Oczekiwanie na sygnał do wznowienia komunikacji międzyprocesowej. */
  189. #ifdef DEBUGPIRNTF
  190.     printf("Przed blokiem\n");
  191. #endif
  192.     sigsuspend (&mask);
  193. #ifdef DEBUGPIRNTF
  194.     printf("Po bloku.\n");
  195. #endif
  196.  
  197. }
  198.  
  199. void sigS3Handler(int signal)
  200. {
  201.     if(*czyTrzeciSygnal)
  202.     {
  203.         *czyTrzeciSygnal = 0;
  204.         for (int i = (ILE_PROCESOW - 1); i >= 0 ; --i)
  205.         {
  206.             if (pids[i] != getpid()) {
  207.                 kill(pids[i], S3);
  208.             }
  209.         }
  210.     }
  211.     *czyDrugiSygnal = 1;
  212. #ifdef DEBUGPIRNTF
  213.     printf("S3 HANDLER pid: %d\n", getpid());
  214. #endif
  215. }
  216.  
  217. int main(int argc, char** argv) {
  218.  
  219.     /* Tworzymy zmienne w pamięci współdzielonej (mmap służy do mapowania plików w pamięci lub jak w tym przypadku(
  220.      * z argumnetem MAP_ANONYMOUS) do towrzenia zmiennych, do których dostęp mogą mieć procesy potomne. */
  221.     pids = mmap(NULL, 3*sizeof(int),
  222.                              PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
  223.                              -1, 0);
  224.  
  225.     czyPierwszySygnal = mmap(NULL, sizeof(short),
  226.                              PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
  227.                              -1, 0);
  228.  
  229.     czyDrugiSygnal = mmap(NULL, sizeof(short),
  230.                           PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
  231.                           -1, 0);
  232.  
  233.     czyTrzeciSygnal = mmap(NULL, sizeof(short),
  234.                            PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
  235.                            -1, 0);
  236.  
  237.     if ( !(pids && czyPierwszySygnal && czyDrugiSygnal && czyTrzeciSygnal) )
  238.     {
  239.         printf("Nie udalo sie utworzyc pamieci wspoldzielonej.\n");
  240.         exit(1);
  241.     }
  242.  
  243.     *czyPierwszySygnal = 1;
  244.     *czyDrugiSygnal = 1;
  245.     *czyTrzeciSygnal = 1;
  246.  
  247.  
  248.     pids[0] = 0;
  249.     pids[1] = 0;
  250.     pids[2] = 0;
  251.  
  252.     int    qid;
  253.     key_t  msgkey;
  254.  
  255.     /* tworzymy wartość klucza IPC */
  256.     msgkey = ftok(".", 'l');
  257.  
  258.     /* otwieramy/tworzymy kolejkę */
  259.     if(( qid = open_queue( msgkey)) == -1) {
  260.         perror("Otwieranie_kolejki");
  261.         POSPRZATAJ();
  262.         exit(1);
  263.     }
  264.     /* ustawiamy umask na 0 aby zapewnić, że prawa do utworzonego pliku FIFO będą takie, jak w wywołaniu funkcji*/
  265.     mode_t stareUmask = umask(0);
  266.     /*Tworzymy fifo */
  267.     mkfifo(SCIEZKA_KOLEJKI_1, 0666);
  268.     /* Przywaracamy umask do poprzednieko stanu*/
  269.     umask(stareUmask);
  270.  
  271.     int forkRet = fork();
  272.  
  273.     if(forkRet == -1)
  274.     {
  275.         perror("Tworzenie procesu:");
  276.         POSPRZATAJ();
  277.         exit(1);
  278.     }
  279.  
  280.     if(forkRet == 0)
  281.     {
  282.         proc1(qid, argc, argv);
  283.         return 0;
  284.     }
  285.     pids[0] = forkRet;
  286.  
  287.     forkRet = fork();
  288.  
  289.     if(forkRet == -1)
  290.     {
  291.         perror("Tworzenie procesu:");
  292.         POSPRZATAJ();
  293.         exit(1);
  294.     }
  295.  
  296.     if(forkRet == 0)
  297.     {
  298.         proc2(qid, SCIEZKA_KOLEJKI_1);
  299.         return 0;
  300.     }
  301.     pids[1] = forkRet;
  302.  
  303.     forkRet = fork();
  304.  
  305.     if(forkRet == -1)
  306.     {
  307.         perror("Tworzenie procesu:");
  308.         POSPRZATAJ();
  309.         exit(1);
  310.     }
  311.  
  312.     if(forkRet == 0)
  313.     {
  314.         proc3(SCIEZKA_KOLEJKI_1);
  315.         return 0;
  316.     }
  317.     pids[2] = forkRet;
  318.  
  319.     printf("Pid procesu 1:%d\nPid procesu 2:%d\nPid procesu 3:%d\n", pids[0], pids[1], pids[2]);
  320.     /* Oczekiwanie aż pracę zakończą procesy kożystające z kolejki komunikatów. */
  321.     wait(&pids[0]);
  322.     wait(&pids[1]);
  323.     /*Usuwamy kolejke*/
  324.     remove_queue(qid);
  325.     /* Czekamy aż ostatni proces, który kożysta z fifo przed zamknięciem go. */
  326.     wait(&pids[2]);
  327.     /*Usuwamy fifo*/
  328.     remove(SCIEZKA_KOLEJKI_1);
  329. #ifdef DEBUGPIRNTF
  330.     printf("Wszystko zakonczylo.\n");
  331. #endif
  332. }
  333.  
  334. int proc1(key_t qid, int argc, char** argv)
  335. {
  336.     /* Ustawia handlery(procedury obsługi) dla poszczególnych syganłów */
  337.     signal(S1, sigS1Handler);
  338.     signal(S2, sigS2Handler);
  339.     signal(S3, sigS3Handler);
  340.     /* Jeśli nie ma argumentów wywołania: tryb interaktywny. */
  341.     if(argc == 1)
  342.     {
  343.         char buf[DLUGOSC_KOMUNIKATU];
  344.         char* fgetsRet = NULL;
  345.         while (1) {
  346.             /* odczytuje kolejne linie z wejscia ( zachowanie gwarantowane dla linni nie dłużych niż długość komunikatu
  347.              * i wysyła je przy użyciu kolejki komuniktaów do procesu 2*/
  348.             again:
  349.             errno = 0;
  350.             fgetsRet = fgets(buf, DLUGOSC_KOMUNIKATU, stdin);
  351.             if (fgetsRet == NULL && errno == EINTR)
  352.                 goto again;
  353.             short czyOstatni = (buf[0] == '\n');
  354.             wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, buf, czyOstatni);
  355.             if (czyOstatni)
  356.                 break;
  357.         }
  358.     }
  359.     /* Argument wywołnia -r: czytanie z pliku /dev/urandom */
  360.     else if(argc == 2 && !strcmp(argv[1],"-r"))
  361.     {
  362.         short czyOstatni = 0;
  363.         ssize_t ileOdczytano = 0;
  364.  
  365.         int fp = open("/dev/urandom", O_RDONLY);
  366.         if(fp == -1)
  367.         {
  368.             /* Nie można uzyskać dostępu do pliku (nie istnieje lub brak uprawnień lub dowolny inny powód
  369.              * Wysyłamy drugiemu procesowi informacje aby zakończył działanie */
  370.             printf("Nie moge uzyskac dostepu do pliku.\n");
  371.             wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, "", 1);
  372.             exit(1);
  373.         }
  374.         /*Czyszczenie bufora*/
  375.         char buf[DLUGOSC_KOMUNIKATU];
  376.         for (int i = 0; i < DLUGOSC_KOMUNIKATU; ++i) {
  377.             buf[i] = '\0';
  378.         }
  379.  
  380.         /* Przesyłanie przy użuyciu kolejki komunikatów dane odczytane z /dev/urandom do drugiego procesu */
  381.         while(1){
  382.             againR:
  383.             errno = 0;
  384.             ileOdczytano = read(fp, buf, DLUGOSC_KOMUNIKATU);
  385.             if(ileOdczytano == -1 && errno == EINTR)
  386.                 goto againR;
  387.             if(ileOdczytano ==0)
  388.             {
  389.                 czyOstatni = 1;
  390.             } else
  391.             {
  392.                 czyOstatni = 0;
  393.             }
  394.             wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, buf, czyOstatni);
  395.             for (int i = 0; i < DLUGOSC_KOMUNIKATU; ++i) {
  396.                 buf[i] = '\0';
  397.             }
  398.             if(ileOdczytano == 0)
  399.                 break;
  400.         }
  401.  
  402.         close(fp);
  403.     }
  404.     /* Argument wywołnia -f: czytanie z pliku podanego jako kolejny argument */
  405.     /* Jak dla arguemtnu wywołania -r tylko ścieżka przyjęta przez użytkownika. */
  406.     else if(argc == 3 && !strcmp(argv[1],"-f"))
  407.     {
  408.         short czyOstatni = 0;
  409.         ssize_t ileOdczytano = 0;
  410.  
  411.         int fp = open(argv[2], O_RDONLY);
  412.  
  413.         if(fp == -1)
  414.         {
  415.             printf("Nie moge uzyskac dostepu do pliku.\n");
  416.             wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, "", 1);
  417.             exit(1);
  418.         }
  419.  
  420.         char buf[DLUGOSC_KOMUNIKATU];
  421.  
  422.         for (int i = 0; i < DLUGOSC_KOMUNIKATU; ++i) {
  423.             buf[i] = '\0';
  424.         }
  425.  
  426.         while(1)
  427.         {
  428.             againF:
  429.             ileOdczytano = read(fp, buf, DLUGOSC_KOMUNIKATU);
  430.             if(ileOdczytano == -1 && errno == EINTR)
  431.                 goto againF;
  432.             if(ileOdczytano ==0)
  433.             {
  434.                 czyOstatni = 1;
  435.             } else
  436.             {
  437.                 czyOstatni = 0;
  438.             }
  439.             wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, buf, czyOstatni);
  440.             for (int i = 0; i < DLUGOSC_KOMUNIKATU; ++i) {
  441.                 buf[i] = '\0';
  442.             }
  443.             if(ileOdczytano == 0)
  444.                 break;
  445.         }
  446.         //wyslijKomunikat(qid, &msg, "", buf, 1);
  447.         close(fp);
  448.     }
  449.     else
  450.     {
  451.     fprintf(stderr,"Nie rozpoznano argumentow wywolania.");
  452.     wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, "", 1);
  453.     }
  454.     return 0;
  455. }
  456.  
  457. int proc2(key_t qid, char* sciezkaKolejki)
  458. {
  459.     signal(S1, sigS1Handler);
  460.     signal(S2, sigS2Handler);
  461.     signal(S3, sigS3Handler);
  462.     char buf[DLUGOSC_KOMUNIKATU];
  463.     int fifo = open(sciezkaKolejki, O_WRONLY);
  464.     do{
  465.         /*Odbieram kolejne komunikaty z kolejki komunikatów i wartości kolejnych bajtów(charów) komunikatu
  466.          * i wypisanie tych bajtów w wyniku konwersji przy użciu funkcji snprintf() do fifo */
  467.         odczytajKomunikat(qid, WIADOMOSC_OD_MASTERA, &msg);
  468.         strncpy(buf, msg.komunikat, DLUGOSC_KOMUNIKATU);
  469.         size_t iloscZnakow = strlen(msg.komunikat);
  470.         char bufKonwersji[3];
  471.         for(int i = 0; i < iloscZnakow; i++)
  472.         {
  473.             snprintf(bufKonwersji, 3, "%02x", msg.komunikat[i]);
  474.             // puts(bufKonwersji);
  475.             again:
  476.             errno = 0;
  477.             if (write(fifo, bufKonwersji, 3) == -1 && errno == EINTR)
  478.                 goto again;
  479.  
  480.         }
  481.     }while(!msg.czyOstatni);
  482. //    remove_queue(qid);
  483.     return 0;
  484. }
  485.  
  486. int proc3(char* sciezkaKolejki)
  487. {
  488.     signal(S1, sigS1Handler);
  489.     signal(S2, sigS2Handler);
  490.     signal(S3, sigS3Handler);
  491.     int fifo = open(sciezkaKolejki, O_RDONLY);
  492.     char buf[3];
  493.     int ileWBuforze = 0;
  494.     char odczytane[15][3];
  495.     ssize_t readRet = 0;
  496.  
  497.     while(1)
  498.     {
  499.         /*Odczytywanie kolejnych skowertowanych bajtów przy użyciu fifo i ponawianie w przypadku
  500.          * przerwania przez sygnał.*/
  501.         again:
  502.         errno = 0;
  503.         readRet = read(fifo, buf, 3);
  504.  
  505.         if (readRet == 0)
  506.             break;
  507.  
  508.         if (readRet == -1 && errno == EINTR)
  509.             goto again;
  510.  
  511.         /* Zapisywanie kolejnego odczytanego z fifo skownwertownaego znaku w buforze */
  512.         strcpy(odczytane[ileWBuforze++], buf);
  513.         /* Jeśli bufor zapełniony wypisujemy dane */
  514.         if(ileWBuforze >= 15)
  515.         {
  516.             int i = 0;
  517.             for(; (ileWBuforze - 1) > i; i++)
  518.             {
  519.                 printf("%s ", odczytane[i]);
  520.             }
  521.             printf("%s\n", odczytane[i]);
  522.             ileWBuforze = 0;
  523.         }
  524.     }
  525.  
  526.     /* Wypisywanie pozostalych elemntów z bufora(jeśli zostaną po wypisaniu ostatniej 15sto znakowej linii */
  527.     if(ileWBuforze > 0)
  528.     {
  529.         int i = 0;
  530.         for(; i < (ileWBuforze - 1); i++)
  531.         {
  532.             printf("%s ", odczytane[i]);
  533.         }
  534.         printf("%s\n", odczytane[i]);
  535.     }
  536.     return 0;
  537. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement