Files
yourchat/server.cpp
2020-06-17 14:33:08 +02:00

179 lines
6.1 KiB
C++
Executable File

#include "server.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <thread>
#include <future>
#include <functional>
#include <unistd.h>
#include <json/json.h>
#include <iostream>
#include <netinet/tcp.h>
#include <sstream>
namespace Yc {
namespace Lib {
Server::Server(Yc::Lib::Config *config) :
_config(config),
_stop(false) {
struct sockaddr_in serverAddr;
int opt = true;
_socket = socket(AF_INET, SOCK_STREAM, 0);
setsockopt(_socket, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt));
int flags = 1;
setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = htons(1235);
if (bind(_socket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) < 0) {
std::cout << "bind not possible" << std::endl;
exit(-1);
}
createRooms(config->group("rooms"));
}
void Server::run() {
if (listen(_socket, 5) < 0) {
std::cout << "listen not possible" << std::endl;
exit(-1);
}
timeval origTv;
origTv.tv_sec = 5;
origTv.tv_usec = 0;
int _maxSd = _socket;
while (!_stop) {
timeval tv(origTv);
fd_set fd;
FD_ZERO(&fd);
FD_SET(_socket, &fd);
if (select(_maxSd + 1, &fd, NULL, NULL, &tv) > 0) {
std::async(std::launch::async, &Server::handleRequest, this);
}
}
}
std::vector<std::string> Server::roomList() {
std::vector<std::string> list;
for (auto &room: _rooms) {
list.push_back(room->name());
}
return list;
}
Json::Value Server::jsonRoomList() {
Json::Value list;
for (auto &room: _rooms) {
Json::Value roomJson = Json::objectValue;
roomJson["name"] = room->name();
roomJson["flags"] = room->flags();
list.append(roomJson);
}
return list;
}
bool Server::roomAllowed(std::string roomName, std::string userName, std::string password){
for (auto &room: _rooms) {
if (room->name() == roomName && room->accessAllowed(userName, password)) {
return true;
}
}
return false;
}
bool Server::changeRoom(User *user, std::string newRoom, std::string password) {
if (!roomAllowed(newRoom, user->name(), password)) {
return false;
}
Json::Value userMsg = Json::objectValue;
userMsg["tr"] = "room_change_user";
userMsg["to"] = newRoom;
for (auto &room: _rooms) {
if (room->userIsInRoom(user->name())) {
room->removeUser(user);
Json::Value msg = Json::objectValue;
msg["tr"] = "room_change_to";
msg["to"] = newRoom;
userMsg["from"] = room->name();
room->addMessage(User::system, msg, user->name(), user->color());
}
}
user->sendMsg(User::system, userMsg, "", "");
for (auto &room: _rooms) {
if (room->name() == newRoom) {
Json::Value msg = Json::objectValue;
msg["tr"] = "room_change_to";
msg["from"] = userMsg["from"];
room->addMessage(User::system, msg, user->name(), user->color());
room->addUserWhenQueueEmpty(user);
}
}
return true;
}
void Server::createRooms(Json::Value roomList) {
for (auto &room: roomList) {
Room *newRoom = new Room(this, room);
_rooms.push_back(newRoom);
}
}
void Server::handleRequest() {
struct sockaddr_in sockAddr;
socklen_t sockAddrLen = sizeof(sockAddr);
int userSock = accept(_socket, (struct sockaddr *)&sockAddr, &sockAddrLen);
if (userSock < 0) {
return;
}
int flags = 1;
setsockopt(userSock, IPPROTO_TCP, TCP_NODELAY, (void *)&flags, sizeof(flags));
std::string msg = readSocket(userSock);
if (msg == "") {
return;
}
inputSwitcher(userSock, msg);
}
void Server::inputSwitcher(int userSocket, std::string input) {
Json::Value inputTree = getJsonTree(input);
if (inputTree["type"] == "init") {
initUser(userSocket, inputTree);
}
}
bool Server::userExists(std::string userName) {
for (auto &room: _rooms) {
if (room->userNameExists(userName)) {
return true;
}
}
return false;
}
void Server::initUser(int userSocket, Json::Value data) {
if (userExists(data["name"].asString())) {
Json::Value errorJson;
errorJson["type"] = User::error;
errorJson["message"] = "loggedin";
send(userSocket, errorJson);
close(userSocket);
return;
}
std::string room = data["room"].asString();
bool added(false);
for (auto &room: _rooms) {
if (room->name() == data["room"].asString()) {
if (room->addUser(data["name"].asString(), data["color"].asString(), data["password"].asString(), userSocket)) {
added = true;
break;
}
}
}
if (!added) {
close(userSocket);
}
}
} // namespace Lib
} // namespace Yp