dns_mastergold.c

来自「C实现的MUD,对大家基本入门网络游戏很有帮助!」· C语言 代码 · 共 887 行 · 第 1/2 页

C
887
字号
// File     : /adm/daemons/network/dns_master.c// Created  : 93-08-09// By       : Grendel@tmi-2// History  : Huthar@Portals wrote the original name server//          : Pinkfish@Discworld wrote a port of the CD udp server.  The//              udp comms and the database code are based on that port.//// This is the daemon that runs the DNS//// What does it do?// -> maintains the database of known muds// -> handles udp communication// -> maintains a list of which services are avaible at which muds// -> maintains an indexed list of outstanding requests to network services// ported to XAJH  by KEN@XAJH  && fuyo@XAJH at 97-1-5#include <ansi.h>#include <mudlib.h>#include <socket_err.h>#include <net/config.h>#include <net/daemons.h>#include <net/dns.h>#include <net/socket.h>#include <net/services.h>#include <net/macros.h>#define DEBUG "debug"#undef DEBUG // services we always query if we don't know about#define STD_SERVICE ({ "mail", "finger", "rwho_q", "tell", "gwizmsg" })// used by the log() function#define MY_LOG_FILE "dns_master"inherit F_DBASE;/* global vars */// the udp port number of the mud, and the socket id of the udp socketprivate int my_port, socket_id;// The mapping containing the general mud info.private mapping muds;// This mapping has an entry for every mud in the dns, and holds// information about the protocols supported for the servicesprivate mapping mud_svc;// Info about ourselvesprivate mapping this_host;// the server where we get our mudlist from, and the number of tries// we have had to contact it.private mixed * bootsrv;private int bootsrv_retry;// used for sequencing the requests to the network servicesprivate int seq_ctr;private mapping seq_entries;// Used for debugging#ifdef DEBUG#  define debug(x) if(monitor) message("diagnostic", (x), monitor)static object monitor = 0;#else#  define debug(x)#endif/* prototypes */// udp communication functionsint startup_udp();void send_udp(string host, int port, string msg);void read_callback(int sock, string msg, string addr);string start_message();// mud database functionsvoid init_database();void refresh_database();void do_pings();void set_mud_info(string name, mapping junk);void zap_mud_info(string name, mapping junk);void support_q_callback(mapping info);private void query_services(string mud, string address, string port, string tcp);// name serving functionsint query_service_method(string mud, string service);mapping query_mud_info(string name);string get_host_name(string alias);int get_mudresource(string mud, string resource);int dns_mudp(string name);mapping query_muds();mapping query_svc();// sequencing functionsvarargs int idx_request(function f);void sequence_callback(int idx, mixed param);void sequence_clean_up();#ifdef DEBUG// debugging functionsmixed * query_bootsrv();void dump_sequencer();void set_monitor(object ob);object query_monitor();#endif// misc functionsprivate void restore_euid();void aux_log(string file, string entry);void aux_warning(string warning);private void log(string entry);void resolve_callback(string address, string my_ip, int key);//	----------------------------------------------------------------------------//	The UDP(User Datagram Protocol) network functions//	----------------------------------------------------------------------------// this function binds our listening socket, and requests a mudlistint startup_udp(){	int err_no;	if (socket_id) return 0;	socket_id = socket_create(DATAGRAM, "read_callback", "close_callback");	if (socket_id < 0) {		log("Failed to acquire socket.\n");		return 0;	}	err_no = socket_bind(socket_id, my_port);	while( err_no == EEADDRINUSE ) {		my_port++;		err_no = socket_bind(socket_id, my_port);	}	if( err_no <= 0 ) {		log( sprintf("Failed to bind socket of UDP services, error = %d.\n", err_no));		socket_close(socket_id);		return 0;	}	return 1;}// this is the function used by the udp slave daemons to send packetsvoid send_udp(string host, int port, string msg){	int sock;	if (!ACCESS_CHECK(previous_object())	&& file_name(previous_object())[0..strlen(AUX_PATH) - 1] != AUX_PATH)		return;#ifdef DEBUG	CHANNEL_D->do_channel(this_object(), "debug", sprintf("sending to %s %s",host,msg[0..10]));#endif	debug("DNS: Sending " + msg);	sock = socket_create(DATAGRAM, "read_callback", "close_callback");	if (sock <= 0) {	    log("Failed to open socket to " + host + " " + port + "\n");	    return;	  }	socket_write(sock, msg, host + " " + port);	socket_close(sock);}// this is called when we receive a udp packet.  We determine which// service the packet is for, and send it to the auxiliary daemon of// that namevoid read_callback(int sock, string msg, string addr){	string func, rest, *bits, name, arg, *list;	mapping args;	int i,flag;	flag = 1;	if(previous_object()) return;	debug("DNS: Got " + msg);	// get the function from the packet	if( !sscanf(msg, "@@@%s||%s@@@%*s", func, rest)) {		if (!sscanf(msg, "@@@%s@@@%*s", func)) return;		rest = "";	}	// get the address(remove port number)	sscanf(addr, "%s %*s", addr);	// get the arguments to the function	// these are in the form "<arg>:<value>" and are put into a mapping	// like that        if (!rest) rest="";        bits = explode(rest, "||");	args = allocate_mapping(sizeof(bits));	i = sizeof(bits);	while (i--)		if (bits[i] && sscanf(bits[i], "%s:%s", name, arg) == 2)			args[name] = arg;	args["HOSTADDRESS"] = addr;	// some muds don 't send their name out in a network friendly form	if (args["NAME"])		args["ALIAS"] = htonn(args["NAME"]);	// we have received a message from someone, so we clear their	// no contact count	if (mapp(muds[args["NAME"]]))		muds[args["NAME"]][DNS_NO_CONTACT] = 0;	// we now execute the function we have received	list = values( LISTNODES );	i = sizeof( list );	while( i-- ) {		sscanf( list[i], "%s %s", bootsrv[0], bootsrv[1] );		// add by ken@XAJH for disable intermud who not define on /include/net/config.h		if( bootsrv[0] == addr && bootsrv[1] == args["PORTUDP"] )			if (file_size(AUX_PATH + func + ".c") > 0) {				flag = 1;			}	}	if( flag ) {		list = values( BANDLIST );		i = sizeof( list );		while( i-- ) {			sscanf( list[i], "%s %s", bootsrv[0], bootsrv[1] );			// add by ken@XAJH for disable intermud who not welcome.			if( bootsrv[0] == addr && bootsrv[1] == args["PORTUDP"] )				flag = 0;		}	}/*	if( func == "mudlist_a" || func == "mudlist_q") {		CHANNEL_D->do_channel(this_object(),"debug",sprintf("Message:%s",msg));		if (args["MUDLIB"] == "Eastern Stories" ) {			flag = 1;		}	}*/	if( flag > 0 )		(AUX_PATH + func + ".c" )->incoming_request(args);#ifdef DEBUGif ( args["PORTUDP"] != 0 )	// add for send intermud functions to a channel by ken@mud.szptt.net.cn at 1997-10-18	CHANNEL_D->do_channel(this_object(),"debug",		sprintf("receive %s host:%s port:%s function: %s",			(flag>0)?"valid":RED"invalid"WHT,addr,args["PORTUDP"], func ));#endif}// used to inform the slave daemons of the udp portint query_udp_port() {	return my_port; }// return the name we'll use on the domain of intermud.string query_mud_name() { return INTERMUD_MUD_NAME; }// this is called when we want to shut the mud downvoid send_shutdown(){	string *mud_names;	int i;	// check the permission	// if(geteuid(previous_object())!= ROOT_UID) return;	// run through the muds and send a shutdown message	mud_names = keys(muds);	i = sizeof(mud_names);	while (i--)		SHUTDOWN->send_shutdown(muds[mud_names[i]]["HOSTADDRESS"],			muds[mud_names[i]]["PORTUDP"]);	socket_close(socket_id);	CHANNEL_D->do_channel(this_object(), "sys", "MUD 互联核心 DNS_MASTER 已经被终止。 \n");}string start_message(){	return sprintf( "||MUDNAME:%s||NAME:%s||VERSION:%s||DRIVER:%s||MUDLIB:%s"		"||HOST:%s||PORT:%d||PORTUDP:%d||TIME:%s||ENCODING:%s||USERS:%d||TCP:%s", 		CHINESE_MUD_NAME,Mud_name(),MUDLIB_VERSION, __VERSION__, MUDLIB_NAME,		query_host_name(),mud_port(), my_port, ctime(time()), MUDLIB_ENCODING,		sizeof(users()), TCP_SERVICE_LEVEL);}//	----------------------------------------------------------------------------//	Network database functions//	----------------------------------------------------------------------------// Sends a startup message to our server mud, then requests a mudlist.// It requests every 60 seconds for 5 minutes.  If it doesn 't get one// by then it switches to the backup server.  It then keeps alternating// until it gets a reply.  If it does switch to the backup server it// doesn't bother checking for the main server, as this would chew cpu// with no real advantage.void init_database(){	int i;	string message, *list; 	// if we have received any muds then we stop starting up.	if( MUDLIST_A->query_db_flag() ) {    	// start call outs - note we do the sequence clean up    	// a bit early because of the number of muds we query    	// when we first start up.    	call_out("refresh_database", REFRESH_INTERVAL);    	call_out("sequence_clean_up", 4 * SERVICE_TIMEOUT);    	do_pings();	// add by ken@XAJH	CHANNEL_D->do_channel(this_object(), "sys", "完成送出 startup 讯息。\n");    	return;    }	message = sprintf("@@@%s%s@@@\n", DNS_STARTUP, start_message());	// send a startup and request a mudlist	list = values( LISTNODES );	i = sizeof( list );	while( i-- ) {		sscanf( list[i], "%s %d", bootsrv[0], bootsrv[1] );		send_udp(bootsrv[0], bootsrv[1], message);		MUDLIST_Q->send_mudlist_q(bootsrv[0], bootsrv[1]);	}	call_out("init_database", 60);	return;}// This periodic function queries the boot server for its current list// of mudsvoid refresh_database(){	int i;	string *list;	while(find_call_out("refresh_database") != -1) { }	call_out("refresh_database", REFRESH_INTERVAL);	list = values( LISTNODES );	i = sizeof( list );  	while( i-- ) {		sscanf( list[i], "%s %d", bootsrv[0], bootsrv[1] );		MUDLIST_Q->send_mudlist_q(bootsrv[0], bootsrv[1]);	}}// this periodic function pings all the muds on our list.  It keeps them// alive in our database, and keeps us alive in theirsvoid do_pings(){	int i;	string *mud_names;	if(find_call_out("do_pings") != -1) return;	// do it again in 30 minutes	call_out("do_pings", PING_INTERVAL);	mud_names = keys(muds);	i = sizeof(mud_names);	while (i--) {		// a static mud		if(undefinedp(mud_svc[mud_names[i]])) continue;		// increment the no contact count - this will be zerod if a reply		// is received, if it reaches a threshold the mud is removed		muds[mud_names[i]] [DNS_NO_CONTACT]++;		// ping the mud		PING_Q->send_ping_q(muds[mud_names[i]]["HOSTADDRESS"],			muds[mud_names[i]]["PORTUDP"]);		// delete it if is hasn 't answered recently enough		if (muds[mud_names[i]][DNS_NO_CONTACT] >= MAX_RETRYS)			zap_mud_info(mud_names[i], 0);	}}// adds a mud to the 'muds' mapping.  if it is a new entry then it may// also query the muds servicesvoid set_mud_info(string name, mapping junk){	string tcp;	if( !(ACCESS_CHECK(previous_object()))	&&	file_name(previous_object())[0..strlen(AUX_PATH) - 1] != AUX_PATH)		return;  	name = htonn( name );	while( name[strlen(name)-1] == '.' ) name = name[ 0..strlen(name)-2 ];	// already know about ourselves	if (name == Mud_name()) return;	junk["ALIAS"] = nntoh( junk["NAME"] );	// determines whether or not we send the service queries out	// to the new mud	if (!undefinedp(mud_svc[name])) {		muds[name] = junk;		return;	}	if (!undefinedp(muds[name]))		this_object()->aux_log("dns_mud_conv", "Udp contact from: "+name+"\n");	// is it a tcp - enabled mud ?	if (!junk["TCP"]) junk["TCP"] = TCP_NONE;	// set the entry in the main mud	muds[name] = junk;	tcp = junk["TCP"];	switch (tcp) {	case TCP_ALL:		mud_svc[name] = ([			"mail"     :  SVC_TCP,			"finger"   :  SVC_TCP | SVC_UDP | SVC_KNOWN,			"tell"     :  SVC_TCP | SVC_UDP | SVC_KNOWN,			"rwho_q"   :  SVC_UDP,			"gwizmsg"  :  SVC_UDP,		]);		break;	case TCP_ONLY:		mud_svc[name] = ([			"mail"     :  SVC_TCP | SVC_NO_UDP | SVC_KNOWN,			"finger"   :  SVC_TCP | SVC_NO_UDP | SVC_KNOWN,			"tell"     :  SVC_TCP | SVC_NO_UDP | SVC_KNOWN,			"rwho_q"   :  SVC_NO_UDP,			"gwizmsg"  :  SVC_NO_UDP,		]);		break;	case TCP_SOME:		mud_svc[name] = ([			"mail"     :  SVC_UNKNOWN,			"finger"   :  SVC_UDP,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?