#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;
}
};
string join = "/join";
set<string> rooms;
vector<Client*> clients;
set<int> meta;
set<int> list;
int metadata = -2;
int port;
int t; // Czy main room
int i, j;
int fdmax = -1; //najwiekszy deskryptor
int listener; //nasluchujacy dekspytor
int newfd; //najnowszy zaakceptowany
int nbytes;
int guest = 0;
int yes = 1;
fd_set master;
fd_set read_fds;
fd_set write_fds;
struct sockaddr_in serveraddr;
struct sockaddr_in serveraddr_meta;
struct sockaddr_in clientaddr;
socklen_t addrlen;
const string delimeterMetaDate = "@@DONE\n";
vector<string> msg_split;
string tt;
int iterator = 0;
int unexpected_error = 0;
string message;
char bufor[256];
size_t fnd;
int size;
void createSocket()
{
if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Server-socket()-listener error");
exit(1);
}
printf("Server-socket()-listener is OK...\n");
}
void createSetSockopt()
{
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");
}
void SetListener()
{
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(port);
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");
}
void CreateMetaData()
{
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(port - 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");
}
bool isMessageAddRoom(string message) {
return message.find(join) != std::string::npos;
}
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 row = to_string(r.desc) + ":" + r.name + ":" + c->Name;
row.append("\n");
sendMessage(m,row);
}
}
sendMessage(m,delimeterMetaDate);
}
}
}
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;
}
void CreateRoom(string text)
{
port++;
vector<string> words_in_message = split(text, ' ');
cout<<"nazwa pokoju" << words_in_message[1] << "|"<<endl;
if (words_in_message.size() < 2) {
cout << "Nie podano nazwy pokoju!" << endl;
return;
}
if (t < 0) {
cout << "Nie mozna tworzyc pokoju!" << endl;
return;
}
string room_name = words_in_message[1];
if (fork() == 0) {
execl("./select", 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);
}
return;
}
}
void ReadMessage()
{
do{
if((size = read(i, &bufor, 256)) <=0){
if(size == 0){// Jeśli 0 to klient się rozłączył
printf("%s: socket %d hung up\n", tt.c_str(), i); //zamkniete
}
else{// Jeśli 0 to klient się rozłączył
perror("recv() error(odbieranie)");
}
close(i); //zamykamy i usuwamy z seta
FD_CLR(i, &master);
list.erase(i);
unexpected_error = 1;
break;
}
//Jeśli znaleziono znak końca wiadomości to break i koniec czytania wiadomości
string wczytane(bufor);
fnd = wczytane.find_first_of("^");//fnd reprezentuje pozycję znaku w stringu
if(fnd != string::npos){// Jeśli nie znajdzie znaku w stringu przyjmuje wartość nops czyli wiadmość się nie skończyła
if (fnd == 0)
break;
wczytane = wczytane.substr(0,fnd);
message.append(wczytane);
break;
}
message.append(wczytane);
}while(fnd == string::npos);// Czytaj dopóki nie wytąpi znak końca
}
void GetMessage()
{
cout<< message<<endl;
msg_split = split(message, ':');
/* aktualizujemy nazwę użytkownika, która była nieznana podczas accepta */
cout<< "0-" << msg_split[0]<<endl;
cout<< "1-"<<msg_split[1]<<endl;
for (Client *c : clients) {
if (c->desc == i && c->Name.find("Guest") >= 0) {
c->Name = msg_split[0];
if (fork()==0) {
sendMetadata();
exit(0);
}
}
}
}
void NewConnect()
{
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(port, "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", tt.c_str() , inet_ntoa(clientaddr.sin_addr), newfd);
}
}
void NewConnectMetaData()
{
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", tt.c_str(), inet_ntoa(clientaddr.sin_addr), newfd);
}
int main(int argc, char* argv[]) {
if (argc < 2) {
cout << "Nie podano portu!" << endl;
return -1;
}
tt = argv[0];
port = stoi(argv[1]);
rooms.insert(tt);
t = tt.find("select");
FD_ZERO(&master);
FD_ZERO(&read_fds);
createSocket();
createSetSockopt();
//set server addr
SetListener();
///////////METADATA//////////////////
if (t >= 0) //czy Main room?
{
CreateMetaData();
}
/* 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) {
NewConnect();
}
else if (i == metadata) {
NewConnectMetaData();
}
else
{
message = "";
//czytanie
ReadMessage();
//update
GetMessage();
if(isMessageAddRoom(msg_split[1]))
{
CreateRoom(msg_split[1]);
}
cout << "Send message: " << message << endl;
/*wysyłanie danych*/
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