1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
|
#include <sys/types.h>
#include <sys/socket.h>
#include <iostream>
#include <cstring>
#include <sstream>
#include <netinet/in.h>
#include <map>
#include <pthread.h>
#include <unistd.h>
#include <time.h>
using namespace std;
int buf_length = 256, nick_length = 16;
typedef map <int, const char*, less <int> > room;
typedef map <const char*, room*, less <const char*> > room_name_glossary;
room_name_glossary rooms;
struct connection_info{
int client;
room* current_room;
};
room* create_room (const char* name);
int is_used (char* nick, room& conn);
const char* get_nickname (int handle, room& current_room);
int make_info (char* info, const char* nick);
void send_to_all (room* current_room, connection_info& con_info, char* buffer, int& result);
room* join_room (int client);
int add_connection (int server);
int change_room (connection_info& con_info, room* previous_room);
void *new_thread (void *arg);
int change_to_new_room (connection_info& con_info, room* previous_room);
inline room* create_room (const char* name) {
room_name_glossary :: iterator i;
for (i = rooms.begin(); i != rooms.end(); i++) {
if (!(strcmp ((*i).first, name))) return (*i).second;
}
room* _new_room = new room;
rooms [&name [0]] = _new_room;
return _new_room;
}
inline int is_used (char* nick, room& conn) { //Checking if there is such a nickname in the map
room :: iterator i;
for (i = conn.begin(); i != conn.end(); i++) {
if (!(strcmp ((*i).second, nick))) return 1;
}
return 0;
}
const char* get_nickname (int handle, room& current_room) {
const char* used_nick_message = "Such a nickname is already being used!\n";
const char* message = "Please, enter your nickname: ";
char* nick = new char [nick_length];
int send_result = send (handle, message, strlen (message), 0);
if (send_result == -1) cerr << "Message sending error! (get_nickname)\n";
int recv_result = recv (handle, &nick [0], nick_length, 0);
if (recv_result == -1) {
cerr << "Nickname receiving error! (get_nickname)\n";
return "GETTING NICKNAME FAILED";
}
while (is_used (nick, current_room)) {
send_result = send (handle, used_nick_message, strlen (used_nick_message), 0);
if (send_result == -1) cerr << "Message sending error! (get_nickname)\n";
send_result = send (handle, message, strlen (message), 0);
if (send_result == -1) cerr << "Message sending error! (get_nickname)\n";
memset (nick, 0, nick_length);
recv_result = recv (handle, &nick [0], nick_length, 0);
if (recv_result == -1) {
cerr << "Nickname receiving error! (get_nickname)\n";
return "GETTING NICKNAME FAILED";
}
}
return nick;
}
int make_info (char* info, const char* nick) { //Composes an information about a sender and sending time
time_t time_sec = time (0);
struct tm* time = localtime (&time_sec);
string buffer;
stringstream hour, min, sec;
hour << time->tm_hour;
min << time->tm_min;
sec << time->tm_sec;
buffer = '[' + hour.str() + ':' + min.str() + ':' + sec.str() + ']' + ' ';
buffer.insert(buffer.length(), nick, strlen(nick));
strcpy (info, buffer.c_str());
return 1;
}
void send_to_all (room* current_room, connection_info& con_info, char* buffer, int& result) {
room :: iterator i;
char* info_line = new char [buf_length];
for (i = (*current_room).begin(); i != (*current_room).end(); i++) { //Sending messages to all the connections
if ((*i).first != con_info.client) {
if (!(make_info (info_line, (*current_room) [con_info.client]))) cerr << "Can't compose sender information!";
int send_result = send ((*i).first, info_line, buf_length, 0);
if (send_result == -1) cerr << "Nickname sending error! (thread)\n";
send_result = send ((*i).first, &buffer [0], result, 0);
if (send_result == -1) {
cerr << "Data sending error! (thread)\n";
break;
}
}
}
delete [] info_line;
}
int change_room (connection_info& con_info, room* previous_room) {
room_name_glossary :: iterator i;
const char* message1 = "None room has been found.\nPlease, enter a name of the new room: ";
const char* message2 = "Please, enter a number of the room:\n";
if (rooms.empty()) send (con_info.client, message1, strlen (message1), 0);
else send (con_info.client, message2, strlen (message2), 0);
for (i = rooms.begin(); i != rooms.end(); i++) { //Shows the list of existing rooms
send (con_info.client, (*i).first, strlen ((*i).first), 0);
}
char* received_index = new char [buf_length];
recv (con_info.client, received_index, buf_length, 0);
stringstream stream;
stream << received_index;
int number;
stream >> number;
i = rooms.begin();
for (int j = 1; j < number; j++) i++;
con_info.current_room = (*i).second;
char* nickname = new char [nick_length];
strcpy (nickname, (*previous_room) [con_info.client]);
(*con_info.current_room)[con_info.client] = nickname; //Rewriting a connection to another room
(*previous_room).erase(con_info.client); //Removing a connection from the previous room
if (previous_room->empty()) {
for (i = rooms.begin(); i != rooms.end(); i++) {
if ((*i).second == previous_room) rooms.erase ((*i).first); //Removing a room from the rooms_map
}
delete previous_room;
}
return 1;
}
int change_to_new_room (connection_info& con_info, room* previous_room) {
return 1;
}
void *new_thread (void *arg) {
connection_info con_info = *(connection_info*)arg;
char* buffer = new char [buf_length];
int result;
room :: iterator i;
do {
result = recv (con_info.client, buffer, buf_length, 0);
if (result == -1) {
cerr << "Data receiving error! (thread)";
break;
}
room* previous_room = con_info.current_room; //In case a client wants to change a room
char* command = buffer;
if (!(strcmp (command, "#CHANGE_ROOM\r\n"))) {
if (!(change_room (con_info, previous_room))) cerr << "Can't change room!";
continue;
}
if (!(strcmp (command, "#CHANGE_TO_NEW\r\n"))) {
if (!(change_to_new_room (con_info, previous_room))) cerr << "Can't change room!";
continue;
}
send_to_all (con_info.current_room, con_info, &buffer [0], result);
} while (result > 0);
delete [] buffer;
delete [] (*con_info.current_room) [con_info.client];
if (!((*con_info.current_room).erase(con_info.client))) cerr << "Map element erasing error! (thread)\n";
close (con_info.client);
return 0;
}
room* join_room (int client) {
char* chosen_room_name = new char [buf_length];
room_name_glossary :: iterator i;
const char* message1 = "None room has been found.\nPlease, enter a name of the new room: ";
const char* message2 = "Please, choose one of the existing rooms or create a new one:\n";
if (rooms.empty()) {
send (client, message1, strlen (message1), 0);
}
else {
send (client, message2, strlen (message2), 0);
for (i = rooms.begin(); i != rooms.end(); i++) { //Shows the list of existing rooms
send (client, (*i).first, strlen ((*i).first), 0);
}
}
int result = recv (client, &chosen_room_name [0], buf_length, 0);
if (result == -1) {
cerr << "Can't receive a room_name!";
return 0;
}
room* chosen_room = create_room (chosen_room_name);
return chosen_room;
}
|