📄 chat.cc
字号:
if (remote_port < 1 || remote_port > 65535) { close(Sprintf("Impossible port number %d", remote_port)); return; } if (inet_addr(ip_address) == (unsigned long)-1) { close (Sprintf("Impossible IP address: %s", ip_address)); return; } ip = ip_address; // Problem: the current version of the zChat specification leaves no delimiter at the end of the // security info section. Zugg suggests just to read whatever has arrived so far and hope for the best // a separrator will appear in the next version of zChat... if (protocol == zchat) { char security_buf[MAX_MUD_BUF]; /* int n =*/ read(security_buf, sizeof(security_buf)); // Check passphrase } state = awaiting_confirmation; if (config->getOption(opt_chat_nodisturb)) rejectConnection(); // Accept all connections? else if (config->getOption(opt_chat_autoaccept)) acceptConnection(); // Accept connection based on security phrase/name else { writeChat("%s has requested a connection. Use %cchat.accept to allow it or %cchat.reject to drop it", shortDescription(), CMDCHAR, CMDCHAR); } } } } else if (state == connecting) { close("Received data while still connecting?!"); } else if (state == connected) { // A command! if (protocol == zchat) { state = waiting_command_header; command_header_received = 0; goto try_again; } else { // One byte-command char cmd; int count = read(&cmd, 1); assert (count == 1); pending_command = cmd; // Now get the data, look out for the 255 character. state = waiting_data; goto try_again; } } else if (state == waiting_data) { char *buf = command_data.get(4096); int n = read(buf, 4096); char *eoc = (char*)memchr(buf, 255, n); if (eoc) { int count = eoc-buf; if (count < n) unread(eoc+1, n - count - 1); // return that many bytes back to the socket buffers command_data.use(eoc-buf); // skip the terminator dispatchCommand(pending_command, ~command_data, command_data.count()); command_data.clear(); state = connected; } else { // otherwise, continue wating for the character command_data.use(n); } } else if (state == waiting_command_header) { int n = read(command_header+command_header_received, 4-command_header_received); assert (n > 0); command_header_received += n; assert (command_header_received <= 4); if (command_header_received == 4) { pending_command = command_header[0] + 256 * command_header[1]; data_length = command_header[2] + 256 * command_header[3]; state = waiting_command_data; if (data_length == 0) { // no data, dispatch right away state = connected; dispatchCommand(pending_command, ~command_data, command_data.count()); command_data.clear(); } else { goto try_again; } } } else if (state == waiting_command_data) { if (data_length > 0) { char *s = command_data.get(data_length); int n = read(s, data_length); data_length -= n; command_data.use(n); } if (data_length == 0) { // Got all the data now state = connected; dispatchCommand(pending_command, ~command_data, command_data.count()); command_data.clear(); goto try_again; } } else if (state == requesting) { // waiting for YES/NO response const char *line = readLine(); if (line) { if (!strncasecmp(line, "NO", 2)) close("Remote reject connection attempt"); else if (!strncasecmp(line, "YES:", 4)) { state = connected; char username[128]; if (1 != sscanf(line, "YES:%s\n", username)) close ("No name specified in initial connection"); else { name = username; writeChat("%s accepted our chat connection", shortDescription()); sendAll(); goto try_again; } } else { close(Sprintf("Strange response: %.64s not YES/NO", line)); } } }}void ChatConnection::sendCommand(int command, const char *data, int len) { if (len == -1) len = strlen(data); if (CDEBUG) writeChat("Sending command %d: %d bytes of data", command, len); if (CDEBUG) writeChat("Data: '%s'", sanitize(data, len, 256)); if (protocol == zchat) { char buf[4]; buf[0] = command % 256; buf[1] = command / 256; buf[2] = len % 256; buf[3] = len / 256; write(buf, sizeof(buf)); if (len > 0) write(data,len); } else { // 255 terminated MudMaster command assert(memchr(data, 255, len) == NULL); // Hmm, how IS it done write(Sprintf("%c", command), 1); write(data, len); write("\377", 1); }}// Return some timestamp in miliseconds. This wraps at 1 millionstatic int getMiliseconds() { struct timeval tv; if (gettimeofday(&tv, NULL) < 0) return 0; else return tv.tv_sec % 1000 + (tv.tv_usec / 1000);}void ChatConnection::dispatchCommand (int command, const char *data, int len) { int stamp_id = -1; // Extract 4-byte stamp ID from zChat if (protocol == zchat && (command == cmdTextPersonal || command == cmdTextGroup || command == cmdTextEverybody)) { if (len < 5) { writeChat("Command %d less than 5 bytes long; cannot have stampID and sufficient text", command); return; } // Byte order ?! Assume raw stamp_id = *(int*)data; data += 4; len -= 4; if (stamp_id == chatServerSocket->getId()) { if (CDEBUG) writeChat("Ignoring duped message: %s", sanitize(data,len,1024)); return; } } const char *sane = sanitize(data, len, 1024); // how much is too much? if (CDEBUG) writeChat("[%s] %d = %s", shortDescription(), command, sane); switch(command) { case cmdTextPersonal: if (!(flags & flagIgnored)) { if (config->getOption(opt_chat_paranoia) || !strstr(sane, ~name)) writeChatText("[%s] %s%c%c", shortDescription(), sane); else writeChatText("%s", sane); } break; case cmdMessage: writeChat("[%s] %s", shortDescription(), sane); break; case cmdPingRequest: sendCommand(cmdPingResponse, data, len); break; case cmdPingResponse: if (len == 4) { int time = *(int*) data; int now = getMiliseconds(); int diff = (now-time + 1000000) % 1000000; writeChat("Ping response from %s: %d.%03ds roundtrip time", shortDescription(), diff/1000, diff%1000); break; } else { writeChat("Invalid ping response from %s: not 4 bytes", shortDescription()); } break; case cmdTextGroup: { char group_name[16]; if (len < (int)sizeof(group_name)) writeChat("Invalid group message, shorter than %d characters", sizeof(group_name)); else { memcpy(group_name, data, sizeof(group_name)-1); group_name[sizeof(group_name)-1] = NUL; data += sizeof(group_name)-1; len -= sizeof(group_name)-1; sane = sanitize(data, len, 1024); for (int i = sizeof(group_name)-1; i >0; i--) if (isspace(group_name[i])) group_name[i] = NUL; if (config->getOption(opt_chat_paranoia) || !strstr(sane, ~name)) writeChatText("[%s] %s", shortDescription(), sane); else writeChatText("%s", sane); // Now propagate this message FOREACH(ChatConnection *, c, chatServerSocket->connections) if (c != this && (c->flags & flagServing) && c->group == group_name) { c->sendText(cmdTextGroup, data); if (CDEBUG) writeChat("Propagating to %s", c->shortDescription()); } } } break; case cmdStamp: if (len < 4) writeChat("Got cmdStamp from %s, but it was only %d bytes long", shortDescription(), len); else { int val = *(int*) data; if (val == chatServerSocket->getId()) { // oh my god, we wore the same thing! writeChat("I have the same StampID as %s -- regenerating mine", shortDescription()); chatServerSocket->generateId(); FOREACH(ChatConnection*,c,chatServerSocket->connections) c->sendStamp(); } } break; case cmdRequestConnections: case cmdPeekConnections: { writeChat("%s asked for a list of our connections", shortDescription()); Buffer b; FOREACH(ChatConnection*,c,chatServerSocket->connections) if (!(c->getFlags() & flagPrivate)) b.printf(",%s,%d", c->getRemoteServerIP(), c->getRemoteServerPort()); if (b.count()) b.shift(1); sendCommand(command == cmdRequestConnections ? cmdConnectionList : cmdPeekList, ~b, b.count()); } break; case cmdConnectionList: case cmdPeekList: { const char *s = sane; char *out, *end; char ip[64], port_s[64]; int port; unsigned int addr; Buffer b; int count = 0, new_connections = 0; if (CDEBUG) writeChat ("con/peek: %s", sane); for (;*s;) { out = ip; end = ip+sizeof(ip)-1; while(*s && *s != ',' && out < end) *out++ = *s++; if (!*s) break; *out = NUL; s++; out = port_s; end = port_s+sizeof(port_s)-1; while(*s && *s != ',' && out < end) *out++ = *s++; *out = NUL; if (*s == ',') s++; port = atoi(port_s); count++; if (port < 1024 || port > 65000) writeChat("%s: discarding %s %d (too high port)", shortDescription(), ip, port); else if (( addr = inet_addr(ip)) == (unsigned int) -1) writeChat("%s: discarding %s %d (invalid IP address)", shortDescription(), ip, port); else { if (command == cmdConnectionList) { if (chatServerSocket->findByAddress(ip, port)) writeChat("%s:%d already exists, not connecting", ip, port); else { // Don't connect to self :) if (strcmp(chatServerSocket->getIPAddress(), ip) || port != chatServerSocket->getLocalPort()) { chatServerSocket->call(ip,port,zchat); new_connections++; } } } else b.printf("%-25s %d\n", ip, port); } } if (command == cmdPeekList) writeChat("%s has %d active connections:\n%s", shortDescription(), count, ~b); else writeChat("%s gave us %d new (total %d) connections", shortDescription(), new_connections, count); } break; case cmdSendCommand: if (flags & flagAllowCommands) { writeChat("%s executes: %s", shortDescription(), sane); interpreter.add(sane); } else { writeChat("%s tries to execute: %s", shortDescription(), sane); sendMessage("You are not allowed to execute commands here"); } break; case cmdTextEverybody: if (!(flags & flagIgnored)) { if (config->getOption(opt_chat_paranoia) || !strstr(sane, ~name)) writeChatText("[%s] %s", shortDescription(), sane); else writeChatText("%s", sane); } // Now propagate this message FOREACH(ChatConnection *, c, chatServerSocket->connections) if (c != this && (c->flags & flagServing)) { c->sendText(cmdTextEverybody, data); if (CDEBUG) writeChat("Propagating to %s", c->shortDescription()); } break; case cmdSnoop: if (flags & flagSnooping) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -