Advertisement
Guest User

Untitled

a guest
Jan 17th, 2019
109
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 14.66 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, oldmask;
  183.     sigfillset (&mask);
  184.     sigdelset(&mask, S1);
  185.     sigdelset(&mask, S2);
  186.     sigdelset(&mask, S3);
  187.     //sigaddset (&mask, SIGCONT);
  188.  
  189.     /* Oczekiwanie na sygnał do wznowienia komunikacji międzyprocesowej. */
  190. #ifdef DEBUGPIRNTF
  191.     printf("Przed blokiem\n");
  192. #endif
  193.     sigsuspend (&mask);
  194. #ifdef DEBUGPIRNTF
  195.     printf("Po bloku.\n");
  196. #endif
  197.  
  198. }
  199.  
  200. void sigS3Handler(int signal)
  201. {
  202.     if(*czyTrzeciSygnal)
  203.     {
  204.         *czyTrzeciSygnal = 0;
  205.         for (int i = (ILE_PROCESOW - 1); i >= 0 ; --i)
  206.         {
  207.             if (pids[i] != getpid()) {
  208.                 kill(pids[i], S3);
  209.             }
  210.         }
  211.     }
  212.     *czyDrugiSygnal = 1;
  213. #ifdef DEBUGPIRNTF
  214.     printf("S3 HANDLER pid: %d\n", getpid());
  215. #endif
  216. }
  217.  
  218. int main(int argc, char** argv) {
  219.  
  220.     /* Tworzymy zmienne w pamięci współdzielonej (mmap służy do mapowania plików w pamięci lub jak w tym przypadku(
  221.      * z argumnetem MAP_ANONYMOUS) do towrzenia zmiennych, do których dostęp mogą mieć procesy potomne. */
  222.     pids = mmap(NULL, 3*sizeof(int),
  223.                              PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
  224.                              -1, 0);
  225.  
  226.     czyPierwszySygnal = mmap(NULL, sizeof(short),
  227.                              PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
  228.                              -1, 0);
  229.  
  230.     czyDrugiSygnal = mmap(NULL, sizeof(short),
  231.                           PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
  232.                           -1, 0);
  233.  
  234.     czyTrzeciSygnal = mmap(NULL, sizeof(short),
  235.                            PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED,
  236.                            -1, 0);
  237.  
  238.     if ( !(pids && czyPierwszySygnal && czyDrugiSygnal && czyTrzeciSygnal) )
  239.     {
  240.         printf("Nie udalo sie utworzyc pamieci wspoldzielonej.\n");
  241.         exit(1);
  242.     }
  243.  
  244.     *czyPierwszySygnal = 1;
  245.     *czyDrugiSygnal = 1;
  246.     *czyTrzeciSygnal = 1;
  247.  
  248.  
  249.     pids[0] = 0;
  250.     pids[1] = 0;
  251.     pids[2] = 0;
  252.  
  253.     int    qid;
  254.     key_t  msgkey;
  255.  
  256.     /* tworzymy wartość klucza IPC */
  257.     msgkey = ftok(".", 'l');
  258.  
  259.     /* otwieramy/tworzymy kolejkę */
  260.     if(( qid = open_queue( msgkey)) == -1) {
  261.         perror("Otwieranie_kolejki");
  262.         POSPRZATAJ();
  263.         exit(1);
  264.     }
  265.  
  266.     mkfifo(SCIEZKA_KOLEJKI_1, 0666);
  267.  
  268.     int forkRet = fork();
  269.  
  270.     if(forkRet == -1)
  271.     {
  272.         perror("Tworzenie procesu:");
  273.         POSPRZATAJ();
  274.         exit(1);
  275.     }
  276.  
  277.     if(forkRet == 0)
  278.     {
  279.         proc1(qid, argc, argv);
  280.         return 0;
  281.     }
  282.     pids[0] = forkRet;
  283.  
  284.     forkRet = fork();
  285.  
  286.     if(forkRet == -1)
  287.     {
  288.         perror("Tworzenie procesu:");
  289.         POSPRZATAJ();
  290.         exit(1);
  291.     }
  292.  
  293.     if(forkRet == 0)
  294.     {
  295.         proc2(qid, SCIEZKA_KOLEJKI_1);
  296.         return 0;
  297.     }
  298.     pids[1] = forkRet;
  299.  
  300.     forkRet = fork();
  301.  
  302.     if(forkRet == -1)
  303.     {
  304.         perror("Tworzenie procesu:");
  305.         POSPRZATAJ();
  306.         exit(1);
  307.     }
  308.  
  309.     if(forkRet == 0)
  310.     {
  311.         proc3(SCIEZKA_KOLEJKI_1);
  312.         return 0;
  313.     }
  314.     pids[2] = forkRet;
  315.  
  316.     printf("Pid procesu 1:%d\nPid procesu 2:%d\nPid procesu 3:%d\n", pids[0], pids[1], pids[2]);
  317.     /* Oczekiwanie aż pracę zakończą procesy kożystające z kolejki komunikatów. */
  318.     wait(&pids[0]);
  319.     wait(&pids[1]);
  320.     /*Usuwamy kolejke*/
  321.     remove_queue(qid);
  322.     /* Czekamy aż ostatni proces, który kożysta z fifo przed zamknięciem go. */
  323.     wait(&pids[2]);
  324.     /*Usuwamy fifo*/
  325.     remove(SCIEZKA_KOLEJKI_1);
  326. #ifdef DEBUGPIRNTF
  327.     printf("Wszystko zakonczylo.\n");
  328. #endif
  329. }
  330.  
  331. int proc1(key_t qid, int argc, char** argv)
  332. {
  333.     /* Ustawia handlery(procedury obsługi) dla poszczególnych syganłów */
  334.     signal(S1, sigS1Handler);
  335.     signal(S2, sigS2Handler);
  336.     signal(S3, sigS3Handler);
  337.     /* Jeśli nie ma argumentów wywołania: tryb interaktywny. */
  338.     if(argc == 1)
  339.     {
  340.         char buf[DLUGOSC_KOMUNIKATU];
  341.         char* fgetsRet = NULL;
  342.         while (1) {
  343.             /* odczytuje kolejne linie z wejscia ( zachowanie gwarantowane dla linni nie dłużych niż długość komunikatu
  344.              * i wysyła je przy użyciu kolejki komuniktaów do procesu 2*/
  345.             again:
  346.             errno = 0;
  347.             fgetsRet = fgets(buf, DLUGOSC_KOMUNIKATU, stdin);
  348.             if (fgetsRet == NULL && errno == EINTR)
  349.                 goto again;
  350.             short czyOstatni = (buf[0] == '\n');
  351.             wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, buf, czyOstatni);
  352.             if (czyOstatni)
  353.                 break;
  354.         }
  355.     }
  356.     /* Argument wywołnia -r: czytanie z pliku /dev/urandom */
  357.     else if(argc == 2 && !strcmp(argv[1],"-r"))
  358.     {
  359.         short czyOstatni = 0;
  360.         ssize_t ileOdczytano = 0;
  361.  
  362.         int fp = open("/dev/urandom", O_RDONLY);
  363.         if(fp == -1)
  364.         {
  365.             /* Nie można uzyskać dostępu do pliku (nie istnieje lub brak uprawnień lub dowolny inny powód
  366.              * Wysyłamy drugiemu procesowi informacje aby zakończył działanie */
  367.             printf("Nie moge uzyskac dostepu do pliku.\n");
  368.             wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, "", 1);
  369.             exit(1);
  370.         }
  371.         /*Czyszczenie bufora*/
  372.         char buf[DLUGOSC_KOMUNIKATU];
  373.         for (int i = 0; i < DLUGOSC_KOMUNIKATU; ++i) {
  374.             buf[i] = '\0';
  375.         }
  376.  
  377.         /* Przesyłanie przy użuyciu kolejki komunikatów dane odczytane z /dev/urandom do drugiego procesu */
  378.         while(1){
  379.             againR:
  380.             errno = 0;
  381.             ileOdczytano = read(fp, buf, DLUGOSC_KOMUNIKATU);
  382.             if(ileOdczytano == -1 && errno == EINTR)
  383.                 goto againR;
  384.             if(ileOdczytano ==0)
  385.             {
  386.                 czyOstatni = 1;
  387.             } else
  388.             {
  389.                 czyOstatni = 0;
  390.             }
  391.             wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, buf, czyOstatni);
  392.             for (int i = 0; i < DLUGOSC_KOMUNIKATU; ++i) {
  393.                 buf[i] = '\0';
  394.             }
  395.             if(ileOdczytano == 0)
  396.                 break;
  397.         }
  398.  
  399.         close(fp);
  400.     }
  401.     /* Argument wywołnia -f: czytanie z pliku podanego jako kolejny argument */
  402.     /* Jak dla arguemtnu wywołania -r tylko ścieżka przyjęta przez użytkownika. */
  403.     else if(argc == 3 && !strcmp(argv[1],"-f"))
  404.     {
  405.         short czyOstatni = 0;
  406.         ssize_t ileOdczytano = 0;
  407.  
  408.         int fp = open(argv[2], O_RDONLY);
  409.  
  410.         if(fp == -1)
  411.         {
  412.             printf("Nie moge uzyskac dostepu do pliku.\n");
  413.             wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, "", 1);
  414.             exit(1);
  415.         }
  416.  
  417.         char buf[DLUGOSC_KOMUNIKATU];
  418.  
  419.         for (int i = 0; i < DLUGOSC_KOMUNIKATU; ++i) {
  420.             buf[i] = '\0';
  421.         }
  422.  
  423.         while(1)
  424.         {
  425.             againF:
  426.             ileOdczytano = read(fp, buf, DLUGOSC_KOMUNIKATU);
  427.             if(ileOdczytano == -1 && errno == EINTR)
  428.                 goto againF;
  429.             if(ileOdczytano ==0)
  430.             {
  431.                 czyOstatni = 1;
  432.             } else
  433.             {
  434.                 czyOstatni = 0;
  435.             }
  436.             wyslijKomunikat(qid, &msg, WIADOMOSC_OD_MASTERA, buf, czyOstatni);
  437.             for (int i = 0; i < DLUGOSC_KOMUNIKATU; ++i) {
  438.                 buf[i] = '\0';
  439.             }
  440.             if(ileOdczytano == 0)
  441.                 break;
  442.         }
  443.         //wyslijKomunikat(qid, &msg, "", buf, 1);
  444.         close(fp);
  445.     }
  446.     return 0;
  447. }
  448.  
  449. int proc2(key_t qid, char* sciezkaKolejki)
  450. {
  451.     signal(S1, sigS1Handler);
  452.     signal(S2, sigS2Handler);
  453.     signal(S3, sigS3Handler);
  454.     char buf[DLUGOSC_KOMUNIKATU];
  455.     int fifo = open(sciezkaKolejki, O_WRONLY);
  456.     do{
  457.         /*Odbieram kolejne komunikaty z kolejki komunikatów i wartości kolejnych bajtów(charów) komunikatu
  458.          * i wypisanie tych bajtów w wyniku konwersji przy użciu funkcji snprintf() do fifo */
  459.         odczytajKomunikat(qid, WIADOMOSC_OD_MASTERA, &msg);
  460.         strncpy(buf, msg.komunikat, DLUGOSC_KOMUNIKATU);
  461.         size_t iloscZnakow = strlen(msg.komunikat);
  462.         char bufKonwersji[3];
  463.         for(int i = 0; i < iloscZnakow; i++)
  464.         {
  465.             snprintf(bufKonwersji, 3, "%02x", msg.komunikat[i]);
  466.             // puts(bufKonwersji);
  467.             again:
  468.             errno = 0;
  469.             if (write(fifo, bufKonwersji, 3) == -1 && errno == EINTR)
  470.                 goto again;
  471.  
  472.         }
  473.     }while(!msg.czyOstatni);
  474. //    remove_queue(qid);
  475.     return 0;
  476. }
  477.  
  478. int proc3(char* sciezkaKolejki)
  479. {
  480.     signal(S1, sigS1Handler);
  481.     signal(S2, sigS2Handler);
  482.     signal(S3, sigS3Handler);
  483.     int fifo = open(sciezkaKolejki, O_RDONLY);
  484.     char buf[3];
  485.     int ileWBuforze = 0;
  486.     char odczytane[15][3];
  487.     ssize_t readRet = 0;
  488.  
  489.     while(1)
  490.     {
  491.         /*Odczytywanie kolejnych skowertowanych bajtów przy użyciu fifo i ponawianie w przypadku
  492.          * przerwania przez sygnał.*/
  493.         again:
  494.         errno = 0;
  495.         readRet = read(fifo, buf, 3);
  496.  
  497.         if (readRet == 0)
  498.             break;
  499.  
  500.         if (readRet == -1 && errno == EINTR)
  501.             goto again;
  502.  
  503.         /* Zapisywanie kolejnego odczytanego z fifo skownwertownaego znaku w buforze */
  504.         strcpy(odczytane[ileWBuforze++], buf);
  505.         /* Jeśli bufor zapełniony wypisujemy dane */
  506.         if(ileWBuforze >= 15)
  507.         {
  508.             int i = 0;
  509.             for(; (ileWBuforze - 1) > i; i++)
  510.             {
  511.                 printf("%s ", odczytane[i]);
  512.             }
  513.             printf("%s\n", odczytane[i]);
  514.             ileWBuforze = 0;
  515.         }
  516.     }
  517.  
  518.     /* Wypisywanie pozostalych elemntów z bufora(jeśli zostaną po wypisaniu ostatniej 15sto znakowej linii */
  519.     if(ileWBuforze > 0)
  520.     {
  521.         int i = 0;
  522.         for(; i < (ileWBuforze - 1); i++)
  523.         {
  524.             printf("%s ", odczytane[i]);
  525.         }
  526.         printf("%s\n", odczytane[i]);
  527.     }
  528.     return 0;
  529. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement