#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