Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream> // cout
- #include <sstream> // cout
- #include <stdlib.h> // exit
- #include <string.h> // bzero
- #include <iostream> // cout
- #include <sstream> // cout
- #include <stdlib.h> // exit
- #include <string.h> // bzero
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <pthread.h>
- #include <postgresql/libpq-fe.h>
- #include <set>
- #include <time.h>
- #include <map>
- using namespace std;
- PGconn *conn;
- //set<int> clients; // o que e um set e um map. Como se introduz num set e num map?
- map<int, string> clientes; // porque tem os 2 maps ? qual e a logica disso?
- //map<string, int> mapas1; // saber ao certo para que servem estas 3 variaveis
- string getNomeUtilizador(int sockfd){
- string user;
- map<int,string>::iterator it = clientes.begin();
- map<int,string>::iterator ite = clientes.end();
- for(;it!=ite;it++){
- if (it->first == sockfd)
- user = it->second;
- }
- return user;
- }
- string get_date() {
- time_t seconds = time(NULL);
- struct tm * timeinfo = localtime(&seconds);
- stringstream oss3;
- oss3 << (timeinfo->tm_year + 1900) << "-" << timeinfo->tm_mon + 1 << "-"
- << timeinfo->tm_mday;
- return oss3.str();
- }
- string get_time() {
- time_t seconds = time(NULL);
- struct tm * timeinfo = localtime(&seconds);
- ostringstream oss4;
- oss4 << timeinfo->tm_hour << ':' << timeinfo->tm_min << ":"
- << timeinfo->tm_sec;
- return oss4.str();
- }
- /* Envia uma string para um socket */
- void writeline(int socketfd, string line) {
- string tosend = line + "\n";
- write(socketfd, tosend.c_str(), tosend.length());
- }
- /* Lê uma linha de um socket
- retorna false se o socket se tiver fechado */
- bool readline(int socketfd, string &line) {
- int n;
- /* buffer de tamanho 1025 para ter espaço
- para o \0 que indica o fim de string*/
- char buffer[1025];
- /* inicializar a string */
- line = "";
- /* Enquanto não encontrarmos o fim de linha
- vamos lendo mais dados da stream */
- while (line.find('\n') == string::npos) {
- // leu n carateres. se for zero chegamos ao fim
- int n = read(socketfd, buffer, 1024); // ler do socket
- if (n == 0)
- return false; // nada para ser lido -> socket fechado
- buffer[n] = 0; // colocar o \0 no fim do buffer
- line += buffer; // acrescentar os dados lidos à string
- }
- // Retirar o \r\n (lemos uma linha mas não precisamos do \r\n)
- line.erase(line.end() - 1);
- line.erase(line.end() - 1);
- return true;
- }
- bool getSalaUtilizador(int origin, int dest){
- string usero, userd;
- ostringstream oss1, oss2;
- usero = getNomeUtilizador(origin);
- userd = getNomeUtilizador(dest);
- oss1 << "SELECT sala FROM users WHERE nick = '" << usero << "'";
- PGresult *result1 = PQexec(conn, oss1.str().c_str());
- oss2 << "SELECT sala FROM users WHERE nick = '" << userd << "'";
- PGresult *result2 = PQexec(conn, oss2.str().c_str());
- if ((PQresultStatus(result1) != PGRES_TUPLES_OK) || (PQresultStatus(result2) != PGRES_TUPLES_OK)) {
- cout << "Failed to execute query " << endl;
- return false;
- }
- string sala1 = PQgetvalue(result1, 0, 0);
- string sala2 = PQgetvalue(result2, 0, 0);
- cout << sala1 << endl;
- cout << sala2 << endl;
- if (sala1 == sala2)
- return true;
- else
- return false;
- }
- /* Envia uma mensagem para todos os clientes ligados exceto 1 */
- void broadcast(int origin, string text) {
- /* Usamos um ostringstream para construir uma string
- Funciona como um cout mas em vez de imprimir no ecrã
- imprime numa string */
- //string user;
- ostringstream oss;
- oss << "(" << get_date() + "|" + get_time() << ")["
- << getNomeUtilizador(origin) << "] "<< " said: " << text;
- map<int,string>::iterator it = clientes.begin();
- map<int,string>::iterator ite = clientes.end();
- if (clientes.size() > 0) {
- for (;it != ite; it++)
- {
- if (it->first != origin)
- {
- if (getSalaUtilizador(origin,it->first))
- {
- writeline(it->first, oss.str());
- }
- }
- }
- }
- else
- {
- writeline(origin, "Tas sozinho oh burro");
- }
- }
- PGconn * ligar_sql() {
- conn = PQconnectdb("host=vdbm.fe.up.pt user=sinf12g81 password=sgvpnu");
- if (PQstatus(conn) == CONNECTION_OK)
- cout << "CONNECTION_OK" << endl;
- //Verifica se há conexão
- if (!conn) {
- cout << "Failed to connect do Database" << endl;
- exit(-1);
- }
- //Verifica se quando há conexão esta está válida, ex: username e password certos
- if (PQstatus(conn) != CONNECTION_OK) {
- cout << "Failed to connect do Database" << endl;
- exit(-1);
- }
- }
- void identify(int sockfd, string line) {
- string comando, nick;
- istringstream iss(line);
- iss >> comando >> nick;
- ostringstream oss1;
- oss1 << "SELECT nick FROM users WHERE nick = '" << nick << "'";
- PGresult *result = PQexec(conn, oss1.str().c_str());
- if (PQresultStatus(result) != PGRES_TUPLES_OK) {
- cout << "Failed to execute query" << ' ' << PQresultStatus(result)
- << endl;
- cout << PQerrorMessage(conn) << endl;
- writeline(sockfd, "Erro ao executar o comando. Por favor, digite identify 'nick'.");
- return;
- }
- if (PQntuples(result) > 0) {
- writeline(sockfd,
- "O Utilizador que pretende utilizar ja existe na base de dados. Para poder fazer identify, escolha outro nick.");
- return;
- } else {
- map<int, string>::iterator it = clientes.begin();
- map<int, string>::iterator ite = clientes.end();
- for (;it != ite; it++) {
- if (it->second == nick) {
- writeline(sockfd,
- "O nick com o qual se pretende identificar ja esta a ser utilizado. Para poder fazer identify, escolha outro nick.");
- return;
- } else {
- for (it = clientes.begin(); it != ite; it++){
- if (it->first == sockfd)
- it->second = nick;
- }
- }
- writeline(sockfd, "Identificacao efectuada com sucesso!");
- return;
- }
- }
- }
- void registo(int sockfd, string line) {
- string comando, user, pass;
- istringstream iss(line);
- iss >> comando >> user >> pass;
- string regist = "";
- ostringstream oss2;
- oss2 << "SELECT nick FROM users WHERE nick = '" << user << "'";
- PGresult *regi = PQexec(conn, oss2.str().c_str());
- if (PQntuples(regi) > 0) {
- writeline(sockfd, "O nick que pretende utilizar ja se encontra registado. Para se registar, escolha outro nick.");
- return;
- } else {
- regist = regist + "INSERT INTO users VALUES ('" + user + "','" + pass
- + "',' 0 ','" + get_date() + "','" + "sala_default" + "','" + get_time() + "";
- PGresult *reg = PQexec(conn, regist.c_str());
- if (PQresultStatus(reg) != PGRES_COMMAND_OK) {
- cout << "Failed to execute query" << ' ' << PQresultStatus(reg)
- << endl;
- } else {
- writeline(sockfd, "Registo efectuado com sucesso! Para fazer login, digite login 'nick' 'password'.");
- }
- return;
- }
- }
- void login(int sockfd, string line) {
- string comando, user, pass;
- istringstream iss(line);
- iss >> comando >> user >> pass;
- string regist = "";
- regist = regist + "SELECT nick, password FROM users WHERE nick='" + user
- + "' and password='" + pass + "'";
- PGresult *log = PQexec(conn, regist.c_str());
- if (PQresultStatus(log) != PGRES_TUPLES_OK) {
- cout << "Failed to execute query " << PQresultStatus(log) << endl;
- return;
- } else if (PQntuples(log) == 1) {
- string updatedata = "";
- updatedata = updatedata + "UPDATE users set data_ultimo_login = '" + get_date() + "' WHERE nick = '" + user + "'";
- PGresult *log2 = PQexec(conn, updatedata.c_str());
- if (PQresultStatus(log2) != PGRES_COMMAND_OK) {
- cout << "Failed to execute query" << ' ' << PQresultStatus(log2) << endl;
- cout << "data"<< endl;
- return;
- }
- string updatehora = "";
- updatehora = updatehora + "UPDATE users set hora_ultimo_login = '" + get_time() + "' WHERE nick = '" + user + "'";
- PGresult *log3 = PQexec(conn, updatehora.c_str());
- if (PQresultStatus(log3) != PGRES_COMMAND_OK) {
- cout << "Failed to execute query" << ' ' << PQresultStatus(log3) << endl;
- cout << "hora"<< endl;
- return;
- }
- string updatedsala = "";
- updatedsala = updatedsala + "UPDATE users set sala = '" + "sala_default" + "' WHERE nick = '" + user + "'";
- PGresult *log4 = PQexec(conn, updatedsala.c_str());
- if (PQresultStatus(log4) != PGRES_COMMAND_OK) {
- cout << "Failed to execute query" << ' ' << PQresultStatus(log4) << endl;
- cout << "sala"<< endl;
- return;
- }
- writeline(sockfd, "Login efectuado com sucesso! =)");
- clientes[sockfd] = user;
- return;
- } else {
- writeline(sockfd,
- "Username ou password incorrectos. =( \n Tente novamente.");
- return;
- }
- }
- void criar(int sockfd, string line) {
- string comando, nomesala, user;
- istringstream iss(line);
- iss >> comando >> nomesala;
- user = getNomeUtilizador(sockfd);
- string regist = "";
- regist = regist + "SELECT nick FROM users WHERE nick='"
- + user + "'";
- PGresult *log = PQexec(conn, regist.c_str());
- if (PQresultStatus(log) != PGRES_TUPLES_OK) {
- cout << "Failed to execute query" << ' ' << PQresultStatus(log) << endl;
- return;
- } else if (PQntuples(log) == 0){
- writeline(sockfd,
- "Necessita de estar logado para criar uma sala.");
- return;
- }
- else {
- string check = "";
- check = check + "SELECT nome_sala FROM rooms WHERE nome_sala='"
- + nomesala + "'";
- PGresult *log2 = PQexec(conn, check.c_str());
- if (PQresultStatus(log2) != PGRES_TUPLES_OK) {
- cout << "Failed to execute query" << ' ' << PQresultStatus(log2) << endl;
- return;
- } else if (PQntuples(log2) > 0)
- {
- writeline(sockfd,"A sala que pretende registar ja foi criada.");
- return;
- }
- ostringstream oss;
- oss << "INSERT INTO rooms VALUES ('" << nomesala << "', '" << user << "');";
- string result = oss.str();
- PGresult *log3 = PQexec(conn, result.c_str());
- if (PQresultStatus(log3) != PGRES_COMMAND_OK) {
- cout << "Failed to execute query " << ' ' << PQresultStatus(log3)
- << endl;
- return;
- }
- writeline(sockfd, nomesala + " Sala criada com sucesso! =)");
- }
- }
- void juntar(int sockfd, string line) {
- string user, comando, room;
- istringstream iss(line);
- iss >> comando >> room;
- user = getNomeUtilizador(sockfd);
- string regist = "";
- regist = regist + "SELECT nome_sala FROM rooms WHERE nome_sala='"
- + room + "'";
- PGresult *log = PQexec(conn, regist.c_str());
- if (PQresultStatus(log) != PGRES_TUPLES_OK) {
- cout << "Failed to execute query" << ' ' << PQresultStatus(log) << endl;
- return;
- } else if (PQntuples(log) == 0){
- writeline(sockfd,"Sala nao existe.");
- return;
- }
- else{
- string junt = "";
- junt = junt + "UPDATE users SET sala = '" + room + "' WHERE nick = '"
- + user + "'";
- PGresult *jun = PQexec(conn, junt.c_str());
- if (PQresultStatus(jun) != PGRES_COMMAND_OK) {
- cout << "Failed to execute query" << ' ' << PQresultStatus(jun) << endl;
- return;
- }
- writeline(sockfd, "Juntou-se a sala " + room + " com sucesso! =)");
- }
- }
- void shout(int sockfd, string line) {
- string comando, mensagem, user;
- istringstream iss(line);
- iss >> comando >> mensagem;
- map<int, string>::iterator it = clientes.begin();
- map<int, string>::iterator ite = clientes.end();
- ostringstream oss;
- for (;it!=ite;it++)
- {
- if (it->first == sockfd)
- oss << "(" << get_date() + "|" + get_time() << ")["
- << it->second << "] "<< " said: " << mensagem;
- }
- string check = "";
- check = check + "SELECT nick, admin FROM users WHERE nick = '" + user + "' and admin= ' 1 '";
- PGresult *log = PQexec(conn, check.c_str());
- if (PQresultStatus(log) != PGRES_TUPLES_OK) {
- cout << "Failed to execute query" << ' ' << PQresultStatus(log) << endl;
- } else if (PQntuples(log) == 0){
- writeline(sockfd,
- " Nao tem permissoes para executar este comando! Para o fazer, necessita de estar registado e logado.");
- return;
- }
- else {
- iss >> comando;
- for (it = clientes.begin();it != ite; it++)
- writeline(it->first, mensagem);
- }
- }
- void whisper(int sockfd, string line) {
- string comando, user, mensagem;
- istringstream iss(line);
- iss >> comando >> user >> mensagem;
- map<int, string>::iterator it = clientes.begin();
- map<int, string>::iterator ite = clientes.end();
- ostringstream oss;
- for (;it!=ite;it++)
- {
- if (it->first == sockfd)
- oss << "(" << get_date() + "|" + get_time() << ")["
- << it->second << "] "<< " said: " << mensagem;
- }
- //comparar com o sql a variavel user e decobrir o seu socket
- string util = "";
- util = util + "SELECT nick FROM users WHERE nick='" + user + "'";
- PGresult *log = PQexec(conn, util.c_str());
- if (PQresultStatus(log) != PGRES_TUPLES_OK) {
- cout << "Failed to execute query" << ' ' << PQresultStatus(log) << endl;
- } else if (PQntuples(log) == 1) {
- map<int,string>::iterator it = clientes.begin();
- map<int,string>::iterator ite = clientes.end();
- for(;it!=ite;it++)
- {
- if (it->second == user)
- writeline(it->first, mensagem);
- }
- } else {
- writeline(sockfd,
- "O utilizador com o qual tentou falar nao existe ou nao esta connectado.");
- }
- }
- void desligar(int sockfd) {
- string regist = "";
- regist = regist + "SELECT nick, admin FROM users WHERE nick='" + getNomeUtilizador(sockfd)
- + "' and admin=' 1 '";
- PGresult *log = PQexec(conn, regist.c_str());
- if (PQresultStatus(log) != PGRES_TUPLES_OK) {
- cout << "Failed to execute query" << ' ' << PQresultStatus(log) << endl;
- } else if (PQntuples(log) == 1) {
- exit(0);
- } else {
- writeline(sockfd, "Nao tem permissoes \n");
- }
- }
- void info(int sockfd, string line) {
- // string comando, nick;
- // istringstream iss(line);
- // iss >> comando >> nick;
- // string regist = "";
- // regist = regist + "SELECT nick FROM users WHERE nick='" + nick + "'";
- // PGresult *log = PQexec(conn, regist.c_str());
- //
- // if (PQresultStatus(log) != PGRES_TUPLES_OK) {
- // cout << "Failed to execute query" << ' ' << PQresultStatus(log) << endl;
- // } else if (PQntuples(log) == 0)
- // writeline(sockfd,
- // "Nao existe um utilizador com esse nome!");
- // else {
- // string regist2 = "";
- // regist2 = regist2 + "SELECT nick, sala, data_ultimo_login, hora_ultimo_login FROM users WHERE nick='" + nick + "'";
- // PGresult *log2 = PQexec(conn, regist.c_str());
- // writeline(sockfd,
- //
- // // falta o write line e saber como vamos buscar o admin sala etc.
- // }
- }
- void ajuda(int sockfd) {
- writeline(
- sockfd,
- "\\identify - Verifica se o utilizador existe na base de dados ou se ja esta conetado. Se ainda nao existir o socket passa a estar associado a este utilizador. Serve para as pessoas se poderem identificar sem terem de criar uma conta.\n Para executar este comando, digite: identify <username> \n");
- writeline(
- sockfd,
- "\\register - Verifica se o utilizador ja existe na base de dados. Se nao existir cria-o e associa o socket ao utilizador criado.\n Para executar este comando, digite: register <username> <password> \n");
- writeline(sockfd,
- "\\login - Para executar este comando, digite: login <username> <password>\n");
- writeline(sockfd, "\\create - Cria uma nova sala de chat. Apenas utilizadores que estejam logados teem permissao para esta aplicacao.\n Para executar este comando, digite: create <room_name> \n");
- writeline(sockfd, "\\join - Permite ao utilizador entrar numa sala.\n Para executar este comando, digite: join <room_name>\n");
- writeline(
- sockfd,
- "\\shout - Enviar uma mensagem para todos os utilizadores (mesmo os de outras salas). So utilizadores com privilegios elevados podem usar esta funcao.\n Para executar este comando, digite: shout <mensagem> \n");
- writeline(sockfd,
- "\\whisper - Enviar uma mensagem a um utilizador específico.\n Para executar este comando, digite: whisper <utilizador> <mensagem> \n");
- writeline(sockfd, "\\exit: Desliga a conexao deste cliente.\n Para executar este comando, digite: exit \n");
- writeline(
- sockfd,
- "\\shutdown: Desliga o servidor. So utilizadores com privilegios elevados podem executar esta funcao.\n Para executar este comando, digite: shutdown \n");
- writeline(sockfd,
- "\\info - Da algumas indicacioes sobre um utilizador especíifico.\n Para executar este comando, digite: info <username> \n");
- }
- /* Trata de receber dados de um cliente cujo socketid foi
- passado como parâmetro */
- void* cliente(void* args) {
- /* quando um utilizador entra, atribui um nome guest + numero de utilizadores online (quando um utilizador sai, a variavel
- * numUtilizadoresOnline decrementa) e adiciona o utilizador ao clientes (e aos mapas???)
- * */
- int sockfd = *(int*) args;
- string line;
- int random = ((rand() % 999) + 1);
- stringstream aux;
- aux << random;
- string nome = "guest" + aux.str();
- pair<int,string> cliente = pair<int,string>(sockfd,nome);
- clientes.insert(cliente);
- // mapas.insert("guest" + numUtilizadoresConnectados,sockfd);
- // cout << "Client connected: " << mapas[sockfd] << endl;
- while (readline(sockfd, line)) {
- cout << "Socket " << sockfd << " said: " << line << endl;
- if (line.find("\\identify") != string::npos)
- identify(sockfd, line);
- else if (line.find("\\register") != string::npos)
- registo(sockfd, line);
- else if (line.find("\\login") != string::npos)
- login(sockfd, line);
- else if (line.find("\\create") != string::npos)
- criar(sockfd, line);
- else if (line.find("\\join") != string::npos)
- juntar(sockfd, line);
- else if (line.find("\\shout") != string::npos)
- shout(sockfd, line);
- else if (line.find("\\whisper") != string::npos)
- whisper(sockfd, line);
- else if (line.find("\\exit") != string::npos)
- break;
- else if (line.find("\\shutdown") != string::npos)
- desligar(sockfd);
- else if (line.find("\\info") != string::npos)
- info(sockfd, line);
- else if (line.find("\\help") != string::npos)
- ajuda(sockfd);
- else
- broadcast(sockfd, line);
- }
- cout << "Client disconnected: " << sockfd << endl;
- clientes.erase(sockfd);
- /* Fechar o socket */
- close(sockfd);
- }
- int main(int argc, char *argv[]) {
- /* Estruturas de dados */
- srand(time(NULL));
- ligar_sql();
- int sockfd, newsockfd, port = 1990;
- socklen_t client_addr_length;
- struct sockaddr_in serv_addr, cli_addr;
- int numClientes;
- /* Inicializar o socket
- AF_INET - para indicar que queremos usar IP
- SOCK_STREAM - para indicar que queremos usar TCP
- sockfd - id do socket principal do servidor
- Se retornar < 0 ocorreu um erro */
- sockfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sockfd < 0) {
- cout << "Error creating socket" << endl;
- exit(-1);
- }
- /* Criar a estrutura que guarda o endereço do servidor
- bzero - apaga todos os dados da estrutura (coloca a 0's)
- AF_INET - endereço IP
- INADDR_ANY - aceitar pedidos para qualquer IP */
- bzero((char *) &serv_addr, sizeof(serv_addr));
- serv_addr.sin_family = AF_INET;
- serv_addr.sin_addr.s_addr = INADDR_ANY;
- serv_addr.sin_port = htons(port);
- /* Fazer bind do socket. Apenas nesta altura é que o socket fica ativo
- mas ainda não estamos a tentar receber ligações.
- Se retornar < 0 ocorreu um erro */
- int res = bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
- if (res < 0) {
- cout << "Error binding to socket" << endl;
- exit(-1);
- }
- /* Indicar que queremos escutar no socket com um backlog de 5 (podem
- ficar até 5 ligações pendentes antes de fazermos accept */
- listen(sockfd, 5);
- while (true) {
- /* Aceitar uma nova ligação. O endereço do cliente fica guardado em
- cli_addr - endereço do cliente
- newsockfd - id do socket que comunica com este cliente */
- client_addr_length = sizeof(cli_addr);
- newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr,
- &client_addr_length);
- /* Criar uma thread para tratar dos pedidos do novo cliente */
- pthread_t thread;
- pthread_create(&thread, NULL, cliente, &newsockfd);
- }
- PQfinish(conn);
- close(sockfd);
- return 0;
- }
Add Comment
Please, Sign In to add comment