- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sstream>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <iostream>
- #include <vector>
- #include <set>
- using namespace std;
- class Room {
- public:
- string name;
- int desc;
- Room(int d, string n) {
- desc = d;
- name = n;
- }
- };
- class Client {
- public:
- int desc;
- string Name;
- vector<Room> rooms;
- Client(int d, string n) {
- desc = d;
- Name = n;
- }
- Client() {}
- };
- vector<string> messagess = { "/join", "/disconnect" };
- set<string> rooms;
- vector<Client*> clients;
- set<int> meta;
- set<int> list;
- int metadata = -2;
- int parseCommand(string message) {
- int result = -1;
- for (auto e : messagess) {
- if (message.find(e) == 0) {
- for (unsigned int i = 0; i < messagess.size(); i++) {
- if (messagess[i] == e)
- result = i;
- }
- }
- }
- return result;
- }
- void sendMessage(int m,string avamys) {
- int sent = 0;
- unsigned int got = 0;
- do {
- sent = send(m, avamys.c_str() + got, avamys.size() - got, MSG_CONFIRM);
- got += sent;
- } while (got < avamys.size());
- }
- void sendMetadata(){
- for (int m: meta){
- if (m != metadata){
- for (Client *c : clients){
- for (Room r : c->rooms){
- string avamys = to_string(r.desc) + ":" + r.name + ":" + c->Name;
- avamys.append("\n");
- sendMessage(m,avamys);
- }
- }
- string avamys = "@@DONE\n";
- sendMessage(m,avamys);
- }
- }
- }
- void split(const string& s, char delim, vector<string>& elems) {
- stringstream ss;
- ss.str(s);
- string item;
- while (getline(ss, item, delim)) {
- elems.push_back(item);
- }
- }
- vector<string> split(const string& s, char delim) {
- vector<string> elems;
- split(s, delim, elems);
- return elems;
- }
- int main(int argc, char* argv[]) {
- if (argc < 2) {
- cout << "Nie podano portu!" << endl;
- return -1;
- }
- rooms.insert(argv[0]);
- fd_set master;
- fd_set read_fds;
- fd_set write_fds;
- struct sockaddr_in serveraddr;
- struct sockaddr_in serveraddr_meta;
- struct sockaddr_in clientaddr;
- int fdmax = -1; //najwiekszy deskryptor
- int listener; //nasluchujacy dekspytor
- int newfd; //najnowszy zaakceptowany
- int nbytes;
- int guest = 0;
- int yes = 1;
- int port = stoi(argv[1]);
- socklen_t addrlen;
- int i, j;
- string tt = argv[0];
- int t = tt.find("select");
- FD_ZERO(&master);
- FD_ZERO(&read_fds);
- if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- {
- perror("Server-socket()-listener error");
- exit(1);
- }
- printf("Server-socket()-listener is OK...\n");
- if (setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
- {
- perror("Server-setsockopt()-listener error");
- exit(1);
- }
- printf("Server-setsockopt()-listener is OK...\n");
- serveraddr.sin_family = AF_INET;
- serveraddr.sin_addr.s_addr = INADDR_ANY;
- serveraddr.sin_port = htons(stoi(argv[1]));
- if (bind(listener, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) == -1)
- {
- perror("Server-bind()-listener error");
- exit(1);
- }
- printf("Server-bind()-listener is OK...\n");
- if (listen(listener, 5) == -1) //kolejka
- {
- perror("Server-listen()-listener error");
- exit(1);
- }
- printf("Server-listen()-listener is OK...\n");
- ///////////METADATA//////////////////
- if (t >= 0) //czy Main room?
- {
- if ((metadata = socket(AF_INET, SOCK_STREAM, 0)) == -1)
- {
- perror("Server-socket()-metadata error");
- exit(1);
- }
- printf("Server-socket()-metadata is OK...\n");
- if (setsockopt(metadata, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
- {
- perror("Server-setsockopt()-metadata error");
- exit(1);
- }
- printf("Server-setsockopt()-metadata is OK...\n");
- serveraddr_meta.sin_family = AF_INET;
- serveraddr_meta.sin_addr.s_addr = INADDR_ANY;
- serveraddr_meta.sin_port = htons(stoi(argv[1]) - 1);
- if (bind(metadata, (struct sockaddr*)&serveraddr_meta, sizeof(serveraddr_meta)) == -1)
- {
- perror("Server-bind()-meta error");
- exit(1);
- }
- printf("Server-bind()-meta is OK...\n");
- if (listen(metadata, 5) == -1) //kolejka
- {
- perror("Server-listen()-metadata error");
- exit(1);
- }
- printf("Server-listen()-metadata is OK...\n");
- }
- /* listener do mastera */
- FD_SET(listener, &master);
- FD_SET(metadata, &master);
- if (listener > fdmax) fdmax = listener;
- if (metadata > fdmax) fdmax = metadata;
- meta.insert(metadata);
- list.insert(listener);
- for (;;){
- read_fds = master;
- if (select(fdmax + 1, &read_fds, NULL, NULL, NULL) == -1) {
- perror("Server-select() error");
- exit(1);
- }
- printf("Server-select() is OK...\n");
- /*szuka po deskryptorach czy cos do czytania*/
- for (i = 0; i <= fdmax; i++) {
- if (FD_ISSET(i, &read_fds)) {
- if (i == listener) {
- /* nowe polaczenia */
- addrlen = sizeof(clientaddr);
- if ((newfd = accept(listener, (struct sockaddr*)&clientaddr, &addrlen)) == -1) {
- perror("Server-accept()-listener error");
- }
- else {
- printf("Server-accept()-listener is OK...\n");
- FD_SET(newfd, &master); /* add to master set */
- list.insert(newfd);
- Client *temp = new Client(newfd, "Guest"+to_string(guest));
- Room ro(stoi(argv[1]), "Main");
- temp->rooms.push_back(ro);
- clients.push_back(temp);
- guest++;
- if (newfd > fdmax) fdmax = newfd;
- printf("%s: New connection from %s on socket %d\n", argv[0], inet_ntoa(clientaddr.sin_addr), newfd);
- }
- }
- else if (i == metadata) {
- /* nowe polaczenia do odczytu metadanych*/
- addrlen = sizeof(clientaddr);
- if ((newfd = accept(metadata, (struct sockaddr*)&clientaddr, &addrlen)) == -1) {
- perror("Server-accept()-metadata error");
- }
- else {
- printf("Server-accept()-metadata is OK...\n");
- meta.insert(newfd);
- }
- if (newfd > fdmax) fdmax = newfd;
- printf("%s: New connection from %s on socket %d\n", argv[0], inet_ntoa(clientaddr.sin_addr), newfd);
- }
- else
- {
- int iterator = 0;
- int unexpected_error = 0;
- int command;
- string message = "";
- char* buf = new char[1024];
- /* czytamy wiadomość */
- do {
- if ((nbytes = recv(i, buf, sizeof(buf), 0)) <= 0) { //zamkniete lub error
- if (nbytes == 0)
- printf("%s: socket %d hung up\n", argv[0], i); //zamkniete
- else
- perror("recv() error(odbieranie)");
- close(i); //zamykamy i usuwamy z seta
- FD_CLR(i, &master);
- list.erase(i);
- unexpected_error = 1;
- break;
- }
- message.append(buf, 0, nbytes);
- iterator += nbytes;
- } while (message[iterator - 1] != '\n');
- if (unexpected_error == 1) continue; // jeśli błąd konczymy obslugę tego klienta w tej iteracji selecta
- vector<string> msg_split = split(message, ':');
- /* aktualizujemy nazwę użytkownika, która była nieznana podczas accepta */
- for (Client *c : clients) {
- if (c->desc == i && c->Name.find("Guest") >= 0) {
- c->Name = msg_split[0];
- if (fork()==0) {
- sendMetadata();
- exit(0);
- }
- }
- }
- /* sprawdzamy czy wiadomość zawiera komendę */
- command = parseCommand(msg_split[1]);
- switch (command) {
- case 0: // join
- port++;
- vector<string> words_in_message = split(msg_split[1], ' ');
- if (words_in_message.size() < 2) {
- cout << "Nie podano nazwy pokoju!" << endl;
- break;
- }
- if (t < 0) {
- cout << "Nie mozna tworzyc pokoju!" << endl;
- break;
- }
- string room_name = words_in_message[1];
- room_name = room_name.substr(0,room_name.size()-2);
- if (fork() == 0) {
- execl("./select.o", room_name.c_str(), (char*)to_string(port).c_str(), nullptr);
- perror("RIP");
- exit(1);
- }
- else {
- /* dodaj pokój do pokoi klienta */
- Room ro(port, room_name);
- for (Client *c: clients) if (c->desc == i) c->rooms.push_back(ro);
- if (fork()==0){
- sendMetadata();
- exit(0);
- }
- break;
- }
- }
- cout << "Zaczynam wysylac: " << message << endl;
- /* mamy dane, trzeba je rozeslac*/
- for (j = 0; j <= fdmax; j++) {
- if (FD_ISSET(j, &master) && list.find(j) != list.end()) {
- if (j != listener) sendMessage(j,message);
- } //if
- } //for
- } //else
- } //if (inset)
- } //for (descs)
- } //for (;;)
- return 1;
- } //main