Facebook
From Sweet Macaw, 6 Years ago, written in C++.
Embed
Download Paste or View Raw
Hits: 225
  1. #include<iostream>
  2. #include<list>
  3. #include<map>
  4. #include<queue>
  5. #include<cstdlib>
  6. #include<thread>
  7. #include<algorithm>
  8. #include<mutex>
  9. #include<netinet/in.h>
  10. #include<sys/socket.h>
  11. #include <sys/types.h>  
  12. #include <fstream>
  13. #include<vector>
  14. #include <unistd.h>
  15. #include <errno.h>
  16.  
  17. #define MAX 256
  18.  
  19. using namespace std;
  20.  
  21. /*
  22.         Struktura opisująca wątek klienta
  23. */
  24. struct client_threads{
  25.         int id_soc;             // Numer gniazda
  26.         int id_user;    // Numer użytkownika
  27.         struct sockaddr_in addrx;       // Adres Gniazda
  28. };
  29.  
  30. /*     
  31.         Struktura opisująca wiadomosc przesyłaną miedzy klientem a serwerem.
  32.         Podczas przesyłu znakiem konca wiadomosci jest ^
  33. */
  34. struct mess{
  35.         int op;         // numer operacji (3 pierwsze / znaki 0-2)
  36.         int id;         // miejsce na id uzytkownika (3 nastepne /znaki 3-5)
  37.         string text;    // wiadomosc (od 6 do znaku konca "^")
  38. };
  39.  
  40. mutex mtx;      //Semafor dostępu do listy klientów
  41. mutex mtx_write;        //Semafor do operacji na plikach
  42. vector<client_threads*> client_list;    //Lista klientów w systemie
  43. vector<int> users_list;         // Lista istniejacych użytkowników naszego chatu
  44.  
  45. int generateID();
  46. void loadUsers();
  47. void service(int my_soc);
  48. void disconnect (int id);
  49. string checkifDigit(string check);
  50. string getHistory(string id);
  51. int find_client(int id_name);
  52. int find_clients(int id_name);
  53. string getFriends(string id);
  54. bool checkUser(string user);
  55. string getPassword(string id);
  56. struct mess recive(int client);
  57. void set_name(int soc, int name);
  58. bool checkFriend(string id,string id_friend);
  59. void createUser(string id, string password);
  60. void addFriend(string id, string id_friend);
  61. string getHistory(string id_from,string id_to);
  62. bool checkifFriend(string user_id, string friend_id);
  63. void SaveAndclearFile(string id_from,string id_to,string text);
  64. void send_message(int fd,string op, string id, string text);
  65. void makeHistory(string id_from,string id_to, string text);
  66.  
  67. int main(int argc, char** argv){
  68.         struct sockaddr_in server_addr;
  69.         socklen_t socket_len;
  70.         int server_socket;
  71.  
  72.         loadUsers();
  73.  
  74.         // Tworzenie gniazda
  75.         if((server_socket = socket(PF_INET, SOCK_STREAM, 0)) != -1)
  76.                 cout << "Utworzona gniazdo serwera... " << endl ;      
  77.         else
  78.                 cout << "Błąd tworzenia gniazda serwera... " << endl ;
  79.  
  80.         int value = 1;
  81.         // Czy port jest zajety
  82.         if(setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &value, sizeof(int) ) < 0)
  83.                 cout << "Błąd setsockopt..." << endl;
  84.  
  85.         server_addr.sin_family = PF_INET;
  86.         server_addr.sin_port = htons(9004);
  87.         server_addr.sin_addr.s_addr = INADDR_ANY;
  88.        
  89.         // Wązanie gniazda
  90.         if(bind (server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) != -1)
  91.                 cout << "Powiązano gniazdo serwera... " << endl ;     
  92.         else
  93.                 cout << "Błąd powiązania gniazda serwera... " << endl ;
  94.  
  95.         // Gniazdo oczekuje nanpolaczenia
  96.         if(listen(server_socket,10) != -1)
  97.                 cout << "Gniazdo serwera w trybie pasywnym... " << endl ;      
  98.         else
  99.                 cout << "Błąd przechodzenia w stan pasywny gniazda serwera... " << endl ;
  100.                        
  101.         while(true){
  102.                 //Tworzenie struktury nowego klienta i akceptacja połączenie
  103.                 client_threads* new_client = new client_threads;
  104.                 socket_len = sizeof(new_client->addrx);
  105.                 if ((new_client->id_soc = accept(server_socket, (struct sockaddr*)&new_client->addrx, &socket_len)) != -1)
  106.                         cout << "Zaakceptowano nowe połączenie... " << endl ;
  107.                 else
  108.                         cout << "Błąd nowego połączenia... " << endl ;
  109.  
  110.                 //Dosanie nowego klienta do listy klientów w systemie
  111.                 mtx.lock();
  112.                 client_list.push_back(new_client);             
  113.                 mtx.unlock();
  114.                
  115.                 //Procedura obsługi klienta
  116.                 thread client_thread(service,new_client->id_soc);
  117.                 client_thread.detach();        
  118.         }      
  119.        
  120.        
  121.         return EXIT_SUCCESS;
  122. }
  123.  
  124. /*
  125. Funkcja obsuługująca klientów
  126. */
  127. void service(int my_soc){
  128.         string send_from; //Login użytkownika obsugiwanego przez wątek (jeśli jest zalogowany)
  129.         struct mess recived_message;//Wiadomość otrzymana od klienta
  130.                
  131.         while(true){
  132.                 recived_message = recive(my_soc);//Odczyt wiadomosci
  133.                 if(recived_message.op == -1){//Zakończenie Połączenia
  134.                         cout << "Brak Połączenia z użytownikiem" << endl;
  135.                         break;         
  136.                 }      
  137.                 switch(recived_message.op){//Obsługa poszczególnych operacji
  138.                         case 0 : { //Log in - Logowanie do serwisu
  139.                                 send_from = to_string(recived_message.id);
  140.                                 if((find_clients(recived_message.id) == -1)  & (recived_message.text.compare(getPassword(to_string(recived_message.id))) == 0)){
  141.                                         set_name(my_soc, recived_message.id);
  142.                                         send_message(my_soc,"000",to_string(recived_message.id),"ok");
  143.                                         cout << "Pomyslne logowanie uzytkownika: " << recived_message.id << endl;
  144.                                 }
  145.                                 else{
  146.                                         send_message(my_soc,"000",to_string(recived_message.id),"0");
  147.                                         cout << "Błąd logowania uzytkownika: " << recived_message.id << endl;
  148.                                 }
  149.                                 break;
  150.                         }
  151.                         case 1 : { //Friends_Send - Wysłanie znajomych użytkownika
  152.                                 send_message(my_soc,"001",send_from, getFriends(to_string(recived_message.id)));
  153.                                 break;
  154.                         }
  155.                         case 2 : { //History_Send - Wysłanie historii konwersacji
  156.                                 send_message(my_soc,"002",to_string(recived_message.id), getHistory(send_from,to_string(recived_message.id)));
  157.                                 break;
  158.                         }
  159.                         /*
  160.                                 Wiadmość wysyłana jeśli obaj użytkownicy mają siebie w liście znajomych.
  161.                                 Jeśli znajomy jest niedostępny wiadomośc jest dopisywana do jego historii
  162.                         */
  163.                         case 3 : { //Send Message - Przesłanie wiadomości
  164.                                 int send_to;
  165.                                 if(checkifFriend(send_from,to_string(recived_message.id)))
  166.                                         if((send_to =  find_client(recived_message.id)) != -1)
  167.                                                 send_message(send_to,"004",send_from, recived_message.text);
  168.                                         else
  169.                                                 makeHistory(send_from, to_string(recived_message.id), send_from + ": " + recived_message.text);
  170.                                 else
  171.                                         send_message(my_soc,"004",to_string(recived_message.id), "SERVER: NIE MAM CIE W ZNAJOMYCH");
  172.                                         ;
  173.                                         break;
  174.                         }
  175.                         case 4 : { //Add New User - Tworzy nowego uzytkownika
  176.                                 int i;
  177.                                 if ((i = generateID()) != -1){
  178.                                         createUser(to_string(i), recived_message.text);
  179.                                         send_message(my_soc,"004",to_string(i), recived_message.text);
  180.                                 }
  181.                                 else
  182.                                         send_message(find_client(recived_message.id),"004","0-1", "Brak Miejsca");
  183.                                 break;
  184.                         }
  185.                         case 5 : { // History_Make - Po przy zamykaniu konwersacji klient wysła cała historie która jest zapisywana
  186.                                 SaveAndclearFile(send_from, to_string(recived_message.id),recived_message.text);
  187.                                 break;
  188.                         }
  189.                         case 6 : { // Friend - Dodaj znajomego do listy
  190.                                 if(checkUser(to_string(recived_message.id))){
  191.                                         addFriend(send_from, to_string(recived_message.id));
  192.                                         send_message(my_soc,"006",to_string(recived_message.id), "1");
  193.                                 }
  194.                                 else
  195.                                         send_message(my_soc,"006",to_string(recived_message.id), "0");
  196.                                 break;
  197.                         }                      
  198.                         default : { // Not defined operation
  199.                                 cout << "Nieznany kod operacji" << endl;
  200.                                 break;
  201.                         }
  202.                 }
  203.         }
  204.  
  205.         disconnect (my_soc);
  206.  
  207.         close(my_soc);
  208. }
  209.  
  210. /*
  211. Nadpisuje całą romowy użytkownika id_from z użytkownikiem id_to
  212. */
  213. void SaveAndclearFile(string id_from,string id_to, string text){
  214.         ofstream currfile;
  215.  
  216.         mtx_write.lock();
  217.         currfile.open(id_from + "/" + id_to +".txt", ios_base::trunc);
  218.         currfile << text;
  219.         currfile.close();
  220.         mtx_write.unlock();
  221. }
  222.  
  223. /*
  224. Sprawdza czy użytkownik friend_id ma w znajomych użytkownika user_id
  225. */
  226. bool checkifFriend(string user_id, string friend_id){
  227.         string line;
  228.  
  229.         mtx_write.lock();
  230.         ifstream currfile(friend_id + "/Friends.txt");
  231.         while(currfile >> line)
  232.                 if (user_id.compare(line) == 0){
  233.                         cout << "foud user " << line << endl;
  234.                         mtx_write.unlock();
  235.                         return true;
  236.                 }
  237.         currfile.close();
  238.         mtx_write.unlock();
  239.         return false;  
  240. }
  241.  
  242. /*
  243. Sprawdza czy użytkownik istnieje
  244. */
  245. bool checkUser(string user){
  246.         string line;
  247.  
  248.         ifstream currfile("Users.txt");
  249.         while(currfile >> line)
  250.                 if (user.compare(line) == 0){
  251.                         cout << "found user " << line << endl;
  252.                         return true;
  253.                 }
  254.         currfile.close();
  255.         return false;  
  256. }
  257.  
  258. /*
  259. Dodaj użutkownika id_friend do znajomych
  260. */
  261. void addFriend(string id, string id_friend){
  262.         ofstream currfile;
  263.  
  264.         mtx_write.lock();
  265.         currfile.open(id + "/Friends.txt", ios_base::app);
  266.         currfile << id_friend + "\n";
  267.         cout << "Added " << id_friend << " to " << id << "/Friends.txt" << endl;
  268.         currfile.close();
  269.         mtx_write.unlock();
  270. }
  271.  
  272. /*
  273. Dopisz wiadomość do historii użytkownika niedostępnego
  274. */
  275. void makeHistory(string id_from,string id_to, string text){
  276.         ofstream currfile;
  277.  
  278.         mtx_write.lock();
  279.         currfile.open(id_to + "/" + id_from +".txt", ios_base::app);
  280.                 currfile << text << "\n";
  281.         currfile.close();
  282.         mtx_write.unlock();
  283. }
  284.  
  285. /*
  286. Uzyskaj historię rozmowy użytkonika id_form z użytkownikiem id_to
  287. */
  288. string getHistory(string id_from,string id_to){
  289.         string history(id_from + "/" + id_to + ".txt"), text, line;
  290.  
  291.         mtx_write.lock();
  292.         ifstream currfile(history);
  293.         while(getline(currfile,line))
  294.                 text.append(line +"\n");
  295.         currfile.close();              
  296.         mtx_write.unlock();
  297.  
  298.         if(!text.empty())
  299.                 return text;
  300.         else
  301.                 return "0";
  302. }
  303.  
  304. /*
  305. Uzyskaj listę znajomych
  306. */
  307. string getFriends(string id){
  308.         string friends(id + "/Friends.txt"), text, line;
  309.         ifstream currfile(friends);
  310.         while(currfile >> line)
  311.                 text.append(line +" ");
  312.         currfile.close();
  313.         return text;   
  314. }
  315.  
  316. /*
  317. Uzyskaj hasło
  318. */
  319. string getPassword(string id){
  320.         string line;
  321.         string password(id + "/Haslo.txt");
  322.  
  323.         ifstream currfile(password);
  324.         getline (currfile,line);
  325.  
  326.         currfile.close();
  327.         return line;
  328. }
  329.  
  330. /*
  331. Stwórz nowego użytkownika
  332. */
  333. void createUser(string id, string password){
  334.         string dir("mkdir " + id);
  335.         ofstream currfile;
  336.  
  337.         system(dir.c_str());
  338.         currfile.open("Users.txt", ios_base::app);
  339.         currfile << id + "\n";
  340.         currfile.close();
  341.         currfile.open(id + "/Haslo.txt");
  342.         currfile << password;
  343.         currfile.close();
  344.         currfile.open(id + "/Friends.txt");
  345.         currfile.close();
  346. }
  347.  
  348. /*
  349. Wczytaj użytkowników
  350. */
  351. void loadUsers(){
  352.         string line;
  353.         ifstream currfile("Users.txt");
  354.         while(currfile >> line)
  355.                 users_list.push_back(stoi(line));
  356.         currfile.close();
  357. }
  358.  
  359. /*
  360. Generuj pierwsze wolne id z przedziału 100-998
  361. */
  362. int generateID(){
  363.         for (int i = 100; i < 999; ++i)
  364.                 if(!(find(users_list.begin(), users_list.end(), i) != users_list.end())){
  365.                         users_list.push_back(i);
  366.                         return i;
  367.                 }
  368.         return -1;
  369. }
  370.  
  371. /*
  372. Usuń klienta z listy podłączonych klientów
  373. */
  374. void disconnect (int soc) {
  375.         mtx.lock();
  376.     for(size_t i=0; i<client_list.size(); ++i)
  377.                 if (client_list[i]->id_soc == soc){
  378.                         delete client_list[i];
  379.                         client_list.erase(client_list.begin() + i);
  380.                         mtx.unlock();
  381.                         return;
  382.                 }
  383.         mtx.unlock();
  384. }
  385.  
  386. /*
  387. Znajdź numer gniazda pod którym znajduje się użytkownik o danym id
  388. */
  389. int find_client(int id_name){
  390.         for(size_t i=0; i<client_list.size(); ++i)
  391.                 if (client_list[i]->id_user == id_name){
  392.                         return client_list[i]->id_soc;
  393.                 }
  394.         return -1;
  395. }
  396.  
  397. /*
  398. Czy dany użytkownik jest zalogowany
  399. */
  400. int find_clients(int id_name){
  401.         for(size_t i=0; i<client_list.size(); ++i)
  402.                 if (client_list[i]->id_user == id_name){
  403.                         return 1;
  404.                 }
  405.         return -1;
  406. }
  407.  
  408. /*
  409. Logowanie - przypisanie użytkownika do danego gniazda
  410. */
  411. void set_name(int soc, int name){
  412.         mtx.lock();
  413.         for(size_t i=0; i<client_list.size(); ++i)
  414.                 if (client_list[i]->id_soc == soc){
  415.                         client_list[i]->id_user = name;
  416.                         mtx.unlock();
  417.                         break;
  418.                 }
  419.         mtx.unlock();
  420. }
  421.  
  422. /*
  423. Wysłanie wiadomości w ustalonym formacie
  424. */
  425. void send_message(int fd,string op, string id, string text){
  426.         string message = op + id + text + "^";
  427.         cout << "Send: " << message << endl;
  428.         write(fd, message.c_str(), message.size());
  429. }
  430.  
  431. /*
  432. Odbiór wiadomości i przetworzenie jej do danej struktury
  433. */
  434. struct mess recive(int client){
  435.         char bufor[MAX];       
  436.         string zdanie;
  437.         size_t fnd;
  438.         struct mess recived;
  439.         int size;
  440.        
  441.         do{
  442.                 size = read(client, &bufor, 256);
  443.                 if(size == 0){// Jeśli 0 to klient się rozłączył  
  444.                         recived.op = -1;
  445.                         return recived;        
  446.                 }
  447.                 if(size == -1){// Jeśli 0 to klient się rozłączył
  448.                         recived.op = -1;                       
  449.                         return recived;        
  450.                 }
  451.  
  452.                 //Jeśli znaleziono znak końca wiadomości to break i koniec czytania wiadomości
  453.                 string wczytane(bufor);
  454.                 fnd = wczytane.find_first_of("^");//fnd reprezentuje pozycję znaku w stringu
  455.                 if(fnd != string::npos){// Jeśli nie znajdzie znaku w stringu przyjmuje wartość nops czyli wiadmość się nie skończyła
  456.                         if (fnd == 0)
  457.                                 break;
  458.                         wczytane = wczytane.substr(0,fnd);
  459.                         zdanie.append(wczytane);
  460.                         break;
  461.                 }
  462.  
  463.                 zdanie.append(wczytane);               
  464.         }while(fnd == string::npos);// Czytaj dopóki nie wytąpi znak końca
  465.        
  466.         //Otrzymana wiadmość
  467.         cout << "Recv: " << zdanie << endl;    
  468.  
  469.         //Sprawdzanie czy wiadomość jest zgodna z ustaloną formą i przekształcenie do struktury
  470.         if (zdanie.size() >= 6){
  471.                 recived.op =  stoi(checkifDigit(zdanie.substr(0,3)));
  472.                 recived.id =  stoi(checkifDigit(zdanie.substr(3,3)));
  473.                 recived.text = zdanie.substr(6);
  474.         }
  475.         else{
  476.                 cout << "Nieodpowiednia ramka" << endl;
  477.                 recived.op = -2;
  478.                 return recived;
  479.         }
  480.  
  481.  
  482.         return recived;
  483. }
  484.  
  485. /*
  486. Sprawdza czy string składa się wyłącznie z cyfr jeśli nie to ustal na -1 tzn. rozłącz
  487. */
  488. string checkifDigit(string check){
  489.         for(size_t i=0; i<check.size(); ++i)
  490.                 if (!isdigit(check[i])){
  491.                         return "0-1";
  492.                         cout << "Złe Dane " << endl;
  493.                 }
  494.         return check;
  495. }
  496.