-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathChatManager.cpp
206 lines (169 loc) · 5.32 KB
/
ChatManager.cpp
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
#include "stdafx.h"
#include "ChatManager.h"
#include <iostream>
#include<string>
typedef void(*ophandler)(Socket* s, int len);
void recvhandle(Socket* s, int len) {
if (len) {
s->onRead();
s->setRecvEvent();
}
else
s->Disconnect();
}
void sendhandle(Socket *s, int len) {
if (len) {
if(s->getsndBuffer()->slen>0)s->getsndBuffer()->slen -=len; //remove sended data len if we didnt
s->setSendEvent(); // IOCP non stop sending over and over dead lock...
}
}
void otherhandle_(Socket *s, int len) {
}
static ophandler ophandlers[] = {
&recvhandle,
&sendhandle,
&otherhandle_
};
chatManager::chatManager() {
}
void chatManager::startListen(void* p) {
chatManager *mng = (chatManager*)p;
mng->server = new chatServer();
mng->server->setChatMngr(mng);
mng->server->acceptThread();
}
void WINAPI chatManager::socketWorkerThread(void *p) {
chatManager *mng = (chatManager*)p;
DWORD len = 0, flags = 0;
LPOVERLAPPED ov = NULL;
Socket *s = nullptr;
OverlappedStruct* o_;
HANDLE cp = mng->getIOCP();
while (true) {
if (!GetQueuedCompletionStatus(cp, &len, (LPDWORD)&s/*when wakes up its returning class that we assigned*/,
&ov/*this important recv or send? data check*/, INFINITE)) {
if (s != nullptr) {
s->Disconnect(); //if GetQueuedCompletionStatus fails (causes connection lost) lets out it
}
}
o_ = CONTAINING_RECORD(ov, OverlappedStruct,m_ov);// remember we created a class that wraps OVERLAPPED struct
// then assigned with 2 obj m_readevent m_sendevent
// this macro returns segment of that m_readeven or m_sendevent
// so we figure out which even has come.
if (o_->getEvent() < Event::NUMOFEVENTNUMBERS) {
ophandlers[o_->getEvent()](s, len);
}
}
}
HANDLE chatManager::getIOCP() { return server->getIOCP(); }
void chatManager::spawnWorkerThreads() {
threads.push_back(new std::thread(startListen, this));
Sleep(1000);// sleep for server start
for (int i = 0; i < 1; i++)// we can create many threads but first we should fix date race condition with creating a mutex class
threads.push_back(new std::thread(socketWorkerThread, this));
}
void chatManager::startChat() {
spawnWorkerThreads();
}
void chatManager::sendToAll(Packet &pkt, Socket* s) {
std::lock_guard<std::mutex> lock(mMutex);
for (auto itr = activeClients.begin(); itr != activeClients.end(); itr++)
(*itr)->Send_(pkt);
}
void chatManager::sendPM(Packet &pkt, Socket* s) {
int id = NULL;
char cid[4];
Packet newpkt;
memcpy(cid, &pkt.data[4], 4); //first 4 characer is "/pm" after that id coming
id = atoi(cid);
if (id >= activeClients.size()) {
std::string er = "Error: there no 1 exist in this id";
memcpy(newpkt.data, er.c_str(), er.size());
newpkt.pkType = PacketType::PM;
s->Send_(newpkt);
return;
}
int senderID = s->getMyID();
std::string str;
str = "PM Message from ";
str += s->getMyNick();
str += "(";
str += _itoa(id, cid, 10);
str += ")";
str += ":";
char temp[500]="\0";
memcpy(temp,&pkt.data[6],494);
str += temp;
newpkt.pkType = pkt.pkType;
memcpy(newpkt.data, str.c_str(), str.size());
activeClients[id]->Send_(newpkt);
}
void chatManager::onDisconnect(Socket *s) {
std::string str;
str = s->getMyNick();
str += " has been disconnected.";
Packet pkt;
pkt.pkType = PacketType::TOALL;
memcpy(pkt.data, str.c_str(), str.size());
sendToAll(pkt, s);
std::cout << inet_ntoa(s->getMyAddr().sin_addr) << str << std::endl;
std::lock_guard<std::mutex> lock(mMutex);
for (auto itr = activeClients.begin(); itr != activeClients.end(); itr++) {
if ((*itr)->getMyID() == s->getMyID()) {
activeClients.erase(itr);
break;
}
}
delete s; //delete it! or leak!!
}
void chatManager::newConnection(Packet &pkt, Socket* s) {
Sleep(100); //need mutex class for remove this shits, causes runtime error
int cid = s->getMyID();
char nick[10];
memcpy(nick, pkt.data, sizeof(nick));
Packet p;
p.pkType = PacketType::NICK;
memcpy(p.data, nick, sizeof(nick));
memcpy(&p.data[sizeof(nick)], " connected!", sizeof(" connected"));
s->setMyNick(nick, 10);
sendToAll(p,s);
}
void chatManager::chatBoard(Packet& pkt, Socket *s) {
Packet npkt;
int id = s->getMyID();
char cid[4];
memcpy(cid, (void *)&id, 4);
Packet newpkt;
std::string str;
str += s->getMyNick();
str += "(";
str += _itoa(id, cid, 10);
str += ")";
str += ":";
str += pkt.data;
npkt.pkType = pkt.pkType;
memcpy(npkt.data, str.c_str(), str.size());
sendToAll(npkt, s);
}
void chatManager::sendList(Socket *s){
Packet pkt;
std::string list;
for (auto itr : activeClients) {
list += itr->getMyNick();
list += "\n";
}
pkt.pkType = PacketType::PM;
memcpy(pkt.data, list.c_str(), list.size());
s->Send_(pkt);
}
void chatManager::HandlePacket(Socket* s) {
Packet pkt; //every packet we should handle in here u can create ur own commands! enjoy fun
pkt.undoPacket(s->getrcvBuffer()->data);
switch (pkt.pkType) {
case PacketType::NICK: newConnection(pkt,s); break;
case PacketType::TOALL: chatBoard(pkt,s); break;
case PacketType::PM: sendPM(pkt,s); break;
case PacketType::CLIST: sendList(s);
default: std::cout << "handle this error!!";
}
}