C ++ (được đánh gôn một phần) 5655 (với CRLF là 1)
Bản biên dịch này trong VS 2013 (sử dụng auto, lambdas và winock) Nó dường như hoạt động trước khi tôi đánh gôn nên trừ khi tôi nhét nó lên thì vẫn ổn. Một trong những lý do rất lớn là các phản hồi số mà tôi trả về bao gồm văn bản được chỉ định trong RFC - Tôi không biết điều đó có cần thiết hay không. Tôi đã thử nghiệm nó với KVirc vì nó chạy ổn định (không được phép cài đặt phần mềm trên PC của tôi!) KVirc dường như hoạt động với máy chủ của tôi nhưng tôi không biết về các khách hàng khác - Tôi đã làm những gì tôi nghĩ RFC nói nhưng rất nhiều về nó không được xác định rõ nên hy vọng tôi hiểu đúng.
Máy chủ xử lý DIE, KILL, NICK, USER, MODE, WHOIS, WHO, THAM GIA, PHẦN, CHỦ ĐỀ, DANH SÁCH, Nnam, PRIVMSG, NGƯỜI DÙNG, PING, PONG và QUIT ở các mức độ khác nhau. Đối với hầu hết trong số họ, tôi trả lại các phản hồi cần thiết bao gồm thực hiện hầu hết các kiểm tra cần thiết để trả về các phản hồi lỗi được chỉ định. Đối với một số người trong số họ tôi gian lận:
- NGƯỜI DÙNG luôn trả lại 446 "NGƯỜI DÙNG đã bị vô hiệu hóa"
- thông báo MODE kênh luôn trả về 477 "Chế độ không hỗ trợ kênh"
- thông báo MODE của người dùng hoạt động đúng nhưng các cờ không được sử dụng bởi các lệnh khác
Tôi nghĩ rằng nó chỉ được đánh gôn một phần vì tôi không giỏi chơi gôn nên nếu bạn thấy điều gì đó lớn lao, hãy chỉnh sửa câu trả lời và sửa nó.
Đây là phiên bản chơi gôn
#include<time.h>
#include<map>
#include<list>
#include<vector>
#include<string>
#include<sstream>
#include<iostream>
#include<algorithm>
#include<winSock2.h>
#pragma comment(lib,"ws2_32.lib")
#define P m.p[0]
#define Q m.p[1]
#define E SOCKET_ERROR
#define I INVALID_SOCKET
#define T c_str()
#define H second
#define Y first
#define S string
#define W stringstream
#define G else
#define J G if
#define A auto
#define Z bool
#define B empty()
#define K return
#define N 513
#define X(n,x)if(x){r=n;goto f;};
#define U(x,i)for(A i=x.begin();i !=x.end();++i)
#define L(x)U(x,i)
#define V(x)for(A i=x.begin();i!=--x.end();++i)
#define M(x)FD_ZERO(&x);FD_SET(t.s,&x);L(l){FD_SET(i->s,&x);}
#define R(a,b,...){M v={a,b,{__VA_ARGS__}};w(d,v);}
#define F(x)}J(!_stricmp(m.c.T,x)){
using namespace std;struct C{S t;list<S>n;};struct M{S f;S c;vector<S>p;};struct D{SOCKET s;SOCKADDR_IN a;int m,l,i;char b[N];S n,u,h,r;time_t p,q;};map<S,C>c;list<D>l;void w(D d,M m);void x(D&t,S r,Z n){L(c)i->H.n.remove(t.n);L(l){A d=*i;if(d.n!=t.n)R(d.n,"QUIT",t.n,r)J(n)R("","ERROR","QUIT",r)}closesocket(t.s);t.s=I;}void w(D d,M m){S s=(!m.p.B?":"+m.f+" ":"")+m.c;V(m.p)s+=" "+*i;s+=" :"+*m.p.rbegin()+"\r\n";int c=0;do{int b=send(d.s,s.T+c,s.size()-c,0);if(b>0)c+=b;G x(d,"send error",0);}while(s.size()-c>0);}Z e(D&d,M m){A z=m.p.size();if(!_stricmp(m.c.T,"DIE")){K 1;F("KILL")if(z<1)R("","461",d.n,"USER","Not enough parameters")G{Z f=0;L(l)if(i->n==P){f=1;x((*i),P,1);}if(f==0)R("","401",d.n,P,"No such nick/channel")}F("NICK")if(z<1)R("","431",d.n,"No nickname given")G{Z f=0;L(l)if(i->n==P)f=1;if(f==1)R("","433",d.n,"Nickname is already in use")G d.n=P;}F("USER")if(z<4)R("","461",d.n,"USER","Not enough parameters")G{Z f=0;L(l)if(i->u==P)f=1;if(f==1)R("","462",d.n,"Unauthorized channel (already registered)")G{d.u=P;d.m=atoi(Q.T);d.h=m.p[2];d.r=m.p[3];R("","001",d.n,"Welcome to the Internet Relay Network "+d.n+"!"+d.u+"@"+d.h)}}F("MODE")if(z<1)R("","461",d.n,"MODE","Not enough parameters")J(P==d.n){if(z<2)R("","221",d.n,S("")+(d.m&2?"+w":"-w")+(d.m&3?"+i":"-i"))G{A x=(147-Q[1])/14;if(Q[0]=='+'){d.m|=1<<x;}G{d.m&=~(1<<x);}}}G R("","477",d.n,P,"Channel doesn't support modes")F("WHOIS")if(z<1)R("","431",d.n,"No nickname given")G{Z f=0;L(l)if(i->n==P){f=1;R("","311",d.n,(i->n,i->u,i->h,"*",i->r))}if(f==1)R("","318",d.n,P,"End of WHOIS")G R("","401",d.n,P,"No such nick/channel")}F("WHO")L(c[P].n)U(l,j)if(*i==j->n)R("","352",d.n,P,j->u,j->h,"*",j->n,"",j->r)R("","315",d.n,P,"End of WHO")F("JOIN")if(z<1)R("","461",d.n,"JOIN","Not enough parameters")J(P=="0")L(c){U(i->H.n,j)if(*j==d.n)R("","PART",i->Y,d.n)i->H.n.remove(d.n);}G{A&C=c[P];Z f=0;L(C.n)if(*i==d.n){f=1;}if(f==0){C.n.push_back(d.n);R(d.n,"JOIN",P)if(C.t.B)R("","331",d.n,P,"No topic is set")G R("","332",d.n,P,C.t)S q;L(C.n)q+=(q.B?"":" ")+*i;R("","353",d.n,"=",P,q)R("","366",d.n,P,"End of NAMES")}}F("PART")if(z<1)R("","461",d.n,"PART","Not enough parameters")G{Z f=0;A&C=c[P];L(C.n)if(*i==d.n)f=1;C.n.remove(d.n);if(f){if(z<2)m.p.push_back(d.n);R(d.n,"PART",P,Q)}G R("","442",d.n,P,"You're not on that channel")}F("TOPIC")if(z<1)R("","461",d.n,"TOPIC","Not enough parameters")G{A&C=c[P];if(z<2){C.t="";R("","331",d.n,P,"No topic is set")}G{C.t=Q;R("","332",d.n,P,C.t)}}F("LIST")if(z<1){L(c){W ss;ss<<i->H.n.size();R("","322",d.n,i->Y,ss.str(),i->H.t.B?"No topic is set":i->H.t)}R("","323",d.n,"End of LIST")}G{W ss;ss<<c[P].n.size();R("","322",d.n,P,ss.str(),c[P].t.B?"No topic is set":c[P].t)R("","323",d.n,"End of LIST")}F("NAMES")if(z<1){L(c){S q;U(i->H.n,j)q+=(q.B?"":" ")+*j;R("","353",d.n,"=",i->Y,q)}R("","366",d.n,"End of NAMES")}G{S q;L(c[P].n)q+=(q.B?"":" ")+*i;R("","353",d.n,"=",P,q)R("","366",d.n,P,"End of NAMES")}F("PRIVMSG")if(z<1)R("","411",d.n,"No recipient given(PRIVMSG)")J(z<2)R("","412",d.n,"No text to send")G{Z f=0;A from=d.n;L(c)if(i->Y==P){f=1;U(i->H.n,k)U(l,j)if(*k==j->n){A d=*j;R(from,"PRIVMSG",d.n,Q)}}if(f==0)L(l)if(i->n==P){f=1;A d=*i;R(from,"PRIVMSG",d.n,Q)}if(f==0)R("","401",d.n,P,"No such nick/channel")}F("USERS")R("","446",d.n,"USERS has been disabled")F("PING")R("","PONG",P,Q)F("PONG")d.p=time(NULL)+60;d.q=0;F("QUIT")if(!z)m.p.push_back(d.n);x(d,P,1);}G{R("","421",d.n,m.c,"Unknown command")}K 0;}M g(char*d){M m;char*n=d;while(*d!='\0'){if(m.c.B){if(*d==':'){for(;*d!='\0'&&*d!=' ';++d);*d='\0';m.f=n+1;n=++d;}for(;*d!='\0'&&*d!=' ';++d);*d='\0';m.c=n;n=++d;}J(*d==':'){for(;*d!='\0';++d);m.p.push_back(n+1);n=++d;}G{for(;*d!='\0'&&*d!=' ';++d);*d='\0';m.p.push_back(n);n=++d;}}K m;}int main(){int r;WSADATA u;SOCKADDR_IN la;la.sin_family=AF_INET;la.sin_port=htons(6667);la.sin_addr.s_addr=htonl(INADDR_ANY);timeval h;h.tv_sec=0;h.tv_usec=10000;fd_set rs,ws,es;D t;t.n="IRCd";X(1,(0!=WSAStartup(MAKEWORD(2,2),&u)))X(2,(I==(t.s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))))X(3,(E==bind(t.s,(SOCKADDR*)&la,sizeof(la))))X(4,(E==listen(t.s,SOMAXCONN)))while(1){M(rs)M(ws)M(es)X(5,(E==select(0,&rs,&ws,&es,&h)))X(6,(FD_ISSET(t.s,&es)))if(FD_ISSET(t.s,&rs)){D d={};d.l=sizeof(d.a);d.s=accept(t.s,(SOCKADDR*)&d.a,&d.l);X(7,(I==d.s))W s;s<<inet_ntoa(d.a.sin_addr)<<":"<<ntohs(d.a.sin_port);d.n=s.str();d.p=time(NULL)+60;d.q=0;l.push_back(d);}L(l){D&d=*i;if(d.p>0&&time(NULL)>d.p){R("","PING",d.n)d.p=0;d.q=time(NULL)+60;}if(d.q>0&&time(NULL)>d.q)x(d,"PONG",1);if(FD_ISSET(d.s,&es))x(d,"select except",0);if(FD_ISSET(d.s,&rs)){int b=recv(d.s,d.b+d.i,sizeof(d.b)-d.i-1>0,0);if(b>0)d.i+=b;G x(d,"recv error",0);char*y=d.b+d.i-2;if(!strcmp(y,"\r\n")){*y++='\0';*y='\0';M m=g(d.b);memset(d.b,0,N);d.i=0;if(d.p>0&&time(NULL)<d.p){d.p=time(NULL)+60;d.q=0;}if(e(d,m))X(0,1)}}}l.remove_if([](const D&d){K d.s==I;});}r=0;f:L(l)x(*i,"exit",0);x(t,"exit",0);WSACleanup();K r;}
Đây là phiên bản hầu hết chưa được chỉnh sửa (vẫn sử dụng một số macro):
#include <time.h>
#include <map>
#include <list>
#include <vector>
#include <string>
#include <sstream>
#include <iostream>
#include <algorithm>
#include <winSock2.h>
#pragma comment(lib, "ws2_32.lib")
#define READ_BUFFER_SIZE 513
#define EXIT_IF(n,x) if (x) { retval=n; goto finished; };
#define LOOPX(x,it) for (auto it = x.begin(); it != x.end(); ++it)
#define LOOP(x) LOOPX(x,it)
#define LOOP2(x) for (auto it = x.begin(); it != --x.end(); ++it)
#define MAKE_SET(x) FD_ZERO(&x); FD_SET(listener.socket, &x); LOOP(socket_list) { FD_SET(it->socket, &x); }
#define RESPOND(a, b, ...) { message response = {a, b, {__VA_ARGS__}}; tell(data, response); }
#define CASE(x) } else if (!_stricmp(msg.command.c_str(),x)) { std::cout << "Received " << x << " from " << data.nickname << std::endl;
struct channel { std::string topic; std::list<std::string> nicknames; };
struct message { std::string prefix; std::string command; std::vector<std::string> params; };
struct socket_data { SOCKET socket; SOCKADDR_IN address; int mode,address_length,read_buffer_index; char read_buffer[READ_BUFFER_SIZE]; std::string nickname,username,servername,realname; time_t ping_timer,pong_timer; };
std::map<std::string,channel> channels;
std::list<socket_data> socket_list;
void tell(socket_data data, message msg);
void disconnect(socket_data& target, std::string reason, bool notify)
{
LOOP(channels) it->second.nicknames.remove(target.nickname);
LOOP(socket_list)
{
auto data = *it;
if (data.nickname != target.nickname) RESPOND(data.nickname, "QUIT", target.nickname, reason)
else if (notify) RESPOND("", "ERROR", "QUIT", reason)
}
closesocket(target.socket);
target.socket = INVALID_SOCKET;
std::cout << "Disconnected " << target.nickname << " reason=" << reason << std::endl;
}
void print(socket_data data, message msg, char *heading)
{
std::cout << heading << ":\n " << inet_ntoa(data.address.sin_addr) << ":" << ntohs(data.address.sin_port) << "\n";
if (!msg.prefix.empty()) std::cout << " Prefix=" << msg.prefix << "\n";
std::cout << " Command=" << msg.command;
int count = 0; LOOP(msg.params) std::cout << "\n Param[" << count++ << "]=" << *it;
std::cout << std::endl;
}
void tell(socket_data data, message msg)
{
print(data, msg, "Response");
std::string str = (!msg.prefix.empty() ? ":" + msg.prefix + " " : "") + msg.command;
LOOP2(msg.params) str += " " + *it;
str += " :" + *msg.params.rbegin() + "\r\n";
int start = 0;
do
{
int bytes = send(data.socket, str.c_str() + start, str.size() - start, 0);
if (bytes > 0) start += bytes; else disconnect(data, "send error", 0);
}
while (str.size() - start > 0);
}
bool process(socket_data &data, message msg)
{
print(data, msg, "Request");
auto size = msg.params.size();
auto first = size<1 ? "" : msg.params[0], second = size<2 ? "" : msg.params[1];
if (!_stricmp(msg.command.c_str(), "DIE")) { return true;
// and now all the cases
CASE("KILL") if (size<1)
RESPOND("", "461", data.nickname, "USER", "Not enough parameters")
else
{
bool found = false;
LOOP(socket_list) if (it->nickname == first) { found = true; disconnect((*it), first, 1); }
if (found == false) RESPOND("", "401", data.nickname, first, "No such nick/channel")
}
CASE("NICK") if (size<1)
RESPOND("", "431", data.nickname, "No nickname given")
else
{
bool found = false;
LOOP(socket_list) if (it->nickname == first) found = true;
if (found == true) RESPOND("", "433", data.nickname, "Nickname is already in use")
else data.nickname = first;
}
CASE("USER") if (size<4)
RESPOND("", "461", data.nickname, "USER", "Not enough parameters")
else
{
bool found = false;
LOOP(socket_list) if (it->username == first) found = true;
if (found == true) RESPOND("", "462", data.nickname, "Unauthorized command (already registered)")
else
{
data.username = first; data.mode = atoi(second.c_str()); data.servername = msg.params[2]; data.realname = msg.params[3];
RESPOND("", "001", data.nickname, "Welcome to the Internet Relay Network " + data.nickname + "!" + data.username + "@" + data.servername)
}
}
CASE("MODE") if (size<1)
RESPOND("", "461", data.nickname, "MODE", "Not enough parameters")
else if (first == data.nickname)
{
if (size < 2)
RESPOND("", "221", data.nickname, std::string("") + (data.mode & 2 ? "+w" : "-w") + (data.mode & 3 ? "+i" : "-i"))
else
{
auto x = (147 - second[1]) / 14;
if (second[0] == '+')
{
data.mode |= 1 << x;
std::cout << "set " << first << " mode bit " << x << "w=2, i=3" << std::endl;
}
else
{
data.mode &= ~(1 << x);
std::cout << "clear " << first << " mode bit " << x << "w=2, i=3" << std::endl;
}
}
}
else
RESPOND("", "477", data.nickname, first, "Channel doesn't support modes")
CASE("WHOIS") if (size < 1)
RESPOND("", "431", data.nickname, "No nickname given")
else
{
bool found = false;
LOOP(socket_list) if (it->nickname == first) { found = true; RESPOND("", "311", data.nickname, (it->nickname, it->username, it->servername, "*", it->realname)) }
if (found == true) RESPOND("", "318", data.nickname, first, "End of WHOIS")
else RESPOND("", "401", data.nickname, first, "No such nick/channel")
}
CASE("WHO") LOOP(channels[first].nicknames) LOOPX(socket_list, dit) if (*it == dit->nickname)
RESPOND("", "352", data.nickname, first, dit->username, dit->servername, "*", dit->nickname, "", dit->realname)
RESPOND("", "315", data.nickname, first, "End of WHO")
CASE("JOIN") if (size < 1)
RESPOND("", "461", data.nickname, "JOIN", "Not enough parameters")
else if (first == "0")
LOOP(channels) { LOOPX(it->second.nicknames, dit) if (*dit == data.nickname) RESPOND("","PART", it->first, data.nickname) it->second.nicknames.remove(data.nickname); }
else
{
auto& channel = channels[first];
bool found = false;
LOOP(channel.nicknames) if (*it == data.nickname) { found = true; }
if (found == false)
{
channel.nicknames.push_back(data.nickname);
RESPOND(data.nickname, "JOIN", first)
if (channel.topic.empty()) RESPOND("", "331", data.nickname, first, "No topic is set")
else RESPOND("", "332", data.nickname, first, channel.topic)
std::string list; LOOP(channel.nicknames) list += (list.empty() ? "" : " ") + *it;
RESPOND("", "353", data.nickname, "=", first, list)
RESPOND("", "366", data.nickname, first, "End of NAMES")
}
}
CASE("PART") if (size < 1)
RESPOND("", "461", data.nickname, "PART", "Not enough parameters")
else
{
bool found = false;
auto &channel = channels[first];
LOOP(channel.nicknames) if (*it == data.nickname) found = true;
channel.nicknames.remove(data.nickname);
if (found)
{
if (size < 2) msg.params.push_back(data.nickname);
RESPOND(data.nickname, "PART", first, second)
}
else RESPOND("", "442", data.nickname, first, "You're not on that channel")
}
CASE("TOPIC") if (size < 1)
RESPOND("", "461", data.nickname, "TOPIC", "Not enough parameters")
else
{
auto& channel = channels[first];
if (size < 2) { channel.topic = ""; RESPOND("", "331", data.nickname, first, "No topic is set") }
else { channel.topic = second; RESPOND("", "332", data.nickname, first, channel.topic) }
}
CASE("LIST") if (size < 1)
{
LOOP(channels)
{
std::stringstream ss; ss << it->second.nicknames.size();
RESPOND("", "322", data.nickname, it->first, ss.str(), it->second.topic.empty() ? "No topic is set" : it->second.topic)
}
RESPOND("", "323", data.nickname, "End of LIST")
}
else
{
std::stringstream ss; ss << channels[first].nicknames.size();
RESPOND("", "322", data.nickname, first, ss.str(), channels[first].topic.empty() ? "No topic is set" : channels[first].topic)
RESPOND("", "323", data.nickname, "End of LIST")
}
CASE("NAMES") if (size < 1)
{
LOOP(channels)
{
std::string list; LOOPX(it->second.nicknames, dit) list += (list.empty() ? "" : " ") + *dit;
RESPOND("", "353", data.nickname, "=", it->first, list)
}
RESPOND("", "366", data.nickname, "End of NAMES")
}
else
{
std::string list; LOOP(channels[first].nicknames) list += (list.empty() ? "" : " ") + *it;
RESPOND("", "353", data.nickname, "=", first, list)
RESPOND("", "366", data.nickname, first, "End of NAMES")
}
CASE("PRIVMSG") if (size < 1)
RESPOND("", "411", data.nickname, "No recipient given (PRIVMSG)")
else if (size < 2)
RESPOND("", "412", data.nickname, "No text to send")
else
{
bool found = false;
auto from = data.nickname;
LOOP(channels) if (it->first == first)
{
found = true;
LOOPX(it->second.nicknames, nit) LOOPX(socket_list, dit) if (*nit == dit->nickname) { auto data = *dit; RESPOND(from, "PRIVMSG", data.nickname, second) }
}
if (found == false)
LOOP(socket_list) if (it->nickname == first)
{
found = true;
auto data = *it; RESPOND(from, "PRIVMSG", data.nickname, second)
}
if (found == false)
RESPOND("", "401", data.nickname, first, "No such nick/channel")
}
CASE("USERS") RESPOND("", "446", data.nickname, "USERS has been disabled")
CASE("PING") RESPOND("", "PONG", first, second)
CASE("PONG") data.ping_timer = time(NULL) + 60; data.pong_timer = 0;
CASE("QUIT") if (!size) msg.params.push_back(data.nickname);
disconnect(data, first, 1);
// end of the cases
} else {
std::cout << "Received invalid message from " << data.nickname << " msg=" << msg.command << std::endl;
RESPOND("", "421", data.nickname, msg.command, "Unknown command")
}
return false;
}
message parse(char *data)
{
message msg;
char *pointer = data;
while (*data != '\0')
{
if (msg.command.empty())
{
if (*data == ':')
{
for (; *data != '\0' && *data != ' '; ++data); *data = '\0';
msg.prefix = pointer + 1;
pointer = ++data;
}
for (; *data != '\0' && *data != ' '; ++data); *data = '\0';
msg.command = pointer;
pointer = ++data;
}
else if (*data == ':')
{
for (; *data != '\0'; ++data);
msg.params.push_back(pointer+1);
pointer = ++data;
}
else
{
for (; *data != '\0' && *data != ' '; ++data); *data = '\0';
msg.params.push_back(pointer);
pointer = ++data;
}
}
return msg;
}
int main()
{
int retval;
WSADATA wsaData;
SOCKADDR_IN listen_address; listen_address.sin_family = AF_INET; listen_address.sin_port = htons(6667); listen_address.sin_addr.s_addr = htonl(INADDR_ANY);
timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = 10000;
fd_set socket_read_set, socket_write_set, socket_except_set;
socket_data listener; listener.nickname = "IRCd";
EXIT_IF(1, (0 != WSAStartup(MAKEWORD(2, 2), &wsaData)))
EXIT_IF(2, (INVALID_SOCKET == (listener.socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))))
EXIT_IF(3, (SOCKET_ERROR == bind(listener.socket, (SOCKADDR *)&listen_address, sizeof(listen_address))))
EXIT_IF(4, (SOCKET_ERROR == listen(listener.socket, SOMAXCONN)))
while (1)
{
MAKE_SET(socket_read_set) MAKE_SET(socket_write_set) MAKE_SET(socket_except_set)
EXIT_IF(5, (SOCKET_ERROR == select(0, &socket_read_set, &socket_write_set, &socket_except_set, &timeout)))
EXIT_IF(6, (FD_ISSET(listener.socket, &socket_except_set)))
if (FD_ISSET(listener.socket, &socket_read_set))
{
socket_data data = {}; // zero everything
data.address_length = sizeof(data.address);
data.socket = accept(listener.socket, (SOCKADDR *)&data.address, &data.address_length);
EXIT_IF(7, (INVALID_SOCKET == data.socket))
std::stringstream ss; ss << inet_ntoa(data.address.sin_addr) << ":" << ntohs(data.address.sin_port); data.nickname = ss.str();
data.ping_timer = time(NULL)+60; data.pong_timer = 0;
socket_list.push_back(data);
std::cout << "Connected " << data.nickname << " ping=" << data.ping_timer << std::endl;
}
LOOP(socket_list)
{
socket_data &data = *it;
if (data.ping_timer > 0 && time(NULL) > data.ping_timer)
{
RESPOND("", "PING", data.nickname)
data.ping_timer = 0; data.pong_timer = time(NULL) + 60;
std::cout << "Sent PING to " << data.nickname << " pong=" << data.pong_timer << std::endl;
}
if (data.pong_timer > 0 && time(NULL) > data.pong_timer) disconnect(data, "PONG", 1);
if (FD_ISSET(data.socket, &socket_except_set)) disconnect(data, "select except", 0);
if (FD_ISSET(data.socket, &socket_read_set))
{
int bytes = recv(data.socket, data.read_buffer + data.read_buffer_index, sizeof(data.read_buffer) - data.read_buffer_index - 1 > 0, 0);
if (bytes > 0) data.read_buffer_index += bytes; else disconnect(data, "recv error", 0);
char *pointer = data.read_buffer + data.read_buffer_index - 2;
if (!strcmp(pointer, "\r\n"))
{
*pointer++ = '\0'; *pointer = '\0'; // remove the \r\n
message msg = parse(data.read_buffer);
memset(data.read_buffer, 0, READ_BUFFER_SIZE); data.read_buffer_index = 0;
if (data.ping_timer > 0 && time(NULL) < data.ping_timer)
{
data.ping_timer = time(NULL) + 60; data.pong_timer = 0;
std::cout << "Reset ping for " << data.nickname << " ping=" << data.ping_timer << std::endl;
}
if (process(data, msg)) EXIT_IF(0, true)
}
}
}
socket_list.remove_if([](const socket_data& data){ return data.socket == INVALID_SOCKET; });
}
retval = 0;
finished:
LOOP(socket_list) disconnect(*it, "exit", 0);
disconnect(listener, "exit", 0);
WSACleanup();
return retval;
}