All pastes #112565 Raw Edit

Untitled

public text v1 · immutable
·published 2006-08-03 01:11 UTC
rendered paste body
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <string>
#include <list>

#include "bzfsAPI.h"

BZ_GET_PLUGIN_VERSION

int sshSock;
std::string cmdLine;
std::string sendBuf;
std::string recvBuf;

void sendCommand(std::string command, std::list<std::string> args) {
	char hex[5];
	for (std::string::iterator i = command.begin(); i != command.end(); i++) {
		sendBuf += '%';
		sprintf(hex, "%-2.2X", *i);
		sendBuf.append(hex);
	}
	for (std::list<std::string>::iterator j = args.begin(); j != args.end(); j++) {
		sendBuf += '|';
		for (std::string::iterator k = j->begin(); k != j->end(); k++) {
			sendBuf += '%' ;
			sprintf(hex, "%-2.2X", *k);
			sendBuf.append(hex);
		}
	}
	sendBuf += '\n';
}

void doCommand(std::string command, std::list<std::string> args) {
	/*
	if (command == "command1") do_1();
	else if (command == "command2") do_2();
	*/
}

void parseCommand(std::string line) {
	int arg = -1;
	std::string curString;
	std::string command;
	std::list<std::string> args;
	
	line += '|';
	for (std::string::iterator i = line.begin(); i != line.end(); i++) {
		switch (*i) {
			case '|': {
				if (arg) command = curString;
				else args.push_back(curString);
				curString = "";
				arg = 0;
			}
			break;
			case '%': {
				char hex[3];
				hex[2] = '\0';
				
				if (++i != line.end() && (hex[0] = *i) && ++i != line.end() && (hex[1] = *i)) {
					unsigned int value;
					
					sscanf(hex, "%X", &value);
					curString += char(value);
				}
				else i = line.end();
			}
			break;
			default:
				curString += *i;
		}
	}
	doCommand(command, args);
}

int spawn (const char* commandLine) {
	int sv[2];
	socketpair(AF_UNIX, SOCK_STREAM, 0, sv);
	
	sendBuf = "";
	recvBuf = "";
	
	std::list<std::string> args;
	args.push_back(bz_getPublicAddr().c_str());
	args.push_back("0");
	args.push_back(bz_getPublicDescription().c_str());
	args.push_back("0");
	args.push_back("");
	args.push_back("");
	sendCommand("server-add", args);
	
	if (!fork()) {
		dup2(sv[1], 0);
		dup2(sv[1], 1);
		
		close(sv[0]);
		close(sv[1]);
		
		execl("/bin/sh", "sh", "-c", commandLine, NULL);
	}
	close(sv[1]);
	return(sv[0]);
}

void bufSock() {
	int n;
	char r;
	while ((n = recv(sshSock, &r, 1, MSG_DONTWAIT)) > 0) {
		if (r == '\n') { parseCommand(recvBuf); recvBuf = ""; }
		else recvBuf += r;
	}
	if (n < 0 && errno == EPIPE) {
		close(sshSock);
		sshSock = spawn(cmdLine.c_str());
	}
	
	n = send(sshSock, sendBuf.c_str(), sendBuf.length(), 0);
	if (n >= 0) sendBuf = sendBuf.substr(n);
	else if (errno == EPIPE) {
		close(sshSock);
		sshSock = spawn(cmdLine.c_str());
	}
}

class BZFX : public bz_EventHandler
{
public:
	virtual void process (bz_EventData *eventData)
	{
		switch (eventData->eventType) {
			case bz_eTickEvent: {
				std::list<std::string> args;
				args.push_back(bz_getPublicAddr().c_str());
				args.push_back(bz_getPublicDescription().c_str());
				args.push_back("0");
				sendCommand("server-update", args);
				
				bufSock();
			}
			break;
		}
	}
};

BZFX bzfx;

BZF_PLUGIN_CALL int bz_Load (const char* commandLine) {
	cmdLine = commandLine;
	
	sshSock = spawn(cmdLine.c_str());
	
	bz_registerEvent(bz_eTickEvent, &bzfx);
	
	bz_debugMessage(4,"BZFX plugin loaded");
	return 0;
}

BZF_PLUGIN_CALL int bz_Unload () {
	bz_removeEvent(bz_eTickEvent, &bzfx);
	
	std::list<std::string> args;
	sendCommand("server-remove", args);

	const char* data = sendBuf.c_str();
	int left = sendBuf.length();
	int total = 0;
	while (left > 0) {
		int n = send(sshSock, data + total, left, 0);

		if (n == -1)
			break;
		
		total += n;
		left -= n;
	}
	close(sshSock);
	
	bz_debugMessage(4,"BZFX plugin unloaded");
	return 0;
}