inetd.c
来自「C实现的MUD,对大家基本入门网络游戏很有帮助!」· C语言 代码 · 共 364 行
C
364 行
/* * Intermud services daemon * Original author: Huthar@Portals * Rewritten: Blackthorn@Genocide (10/29/92) * Cleaned up and unflakified by Truilkan@Basis (11/21/92) * Removed a redundant map_delete() call - Truilkan (11/21/92) * 93-07-30 Grendel@tmi-2 Removed defines, replaced with inetd.h */ #include <config.h>#include <net/daemons.h>#include <net/socket.h>#include <net/inetd.h>#include <net/macros.h>#define log(x) log_file("inetd", (x))// function protypesvoid possible_close(int id);string read_socket(int id);int write_socket(int id, string msg);void load_services();void create_listen_socket();void close_socket(int id);void close_callback(int fd);void write_callback(int id);void read_callback(int fd, string msg);int create_socket(string dest);int open_service(string mud, string svc, string *parms);void process_incoming(int fd);// globalsint listen_fd;mapping sockets, service; // indexed on numerical socket id // "incoming": incoming data waiting to be read // "outgoing": outgoing data waiting to be written // "owner": object that owns the socket // "wcb_pending": a write callback is pending on this socket // "closing": no further operations should be permitted on this socket // "read_callback": name of the owner's read callback function // "close_callback": name of the owner's close callback function // "service_callback": name of the owner's "service callback" function // "fd": socket's file descriptor // "service_desired": service that we want from the remote mapping service; // indexed on service name, contains string filename of server object voidpossible_close(int id){ if (!sockets[id]) { return; } if (sockets[id]["closing"]) { if (!strlen(sockets[id]["outgoing"]) && !strlen(sockets[id]["incoming"])) { socket_close(sockets[id]["fd"]); } }} stringread_socket(int id){ int error; if (!sockets[id] || ((previous_object() != this_object()) && (previous_object() != sockets[id]["owner"]))) { log("read_socket: security violation on socket id " + id + "\n"); return 0; } if (strlen(sockets[id]["incoming"]) > 0) { string rcv; rcv = sockets[id]["incoming"]; sockets[id]["incoming"] = ""; possible_close(id); return rcv; } else return 0;}intwrite_socket(int id, string msg){ int error; if (!sockets[id] || ((previous_object() != this_object()) && (previous_object() != sockets[id]["owner"]))) { log("write_socket: security violation on socket id " + id + "\n"); return 0; } // it used to check for "closing" status here, but we should first be // allowed to empty out the "incoming" and "outgoing" buffers. // Patch by Zazz@WizMud, 3/26/93. if (sockets[id]["wcb_pending"]) { sockets[id]["outgoing"] += msg; } else { error = socket_write(sockets[id]["fd"], msg); if (error != EESUCCESS) { // on some machines this happens *alot* if (error == EEALREADY) { sockets[id]["outgoing"] += msg; // data *not* buffered sockets[id]["wcb_pending"] = 1; } if (error==EECALLBACK) { sockets[id]["wcb_pending"] = 1; } else return 0; } } // NOW check to see if the server has indicated it is through if (sockets[id]["closing"] == 1) { possible_close(id); // will close iff buffers empty return 0; } return 1;} voidload_services(){ string file, *lines, svc; string path; int i; service = ([]); file = read_file(INETD_SERVICES); if (!file) { log("load_services: cannot read inetd services file " + INETD_SERVICES + "\n"); return; } lines = explode(file, "\n"); for (i = 0; i < sizeof(lines); i++) { if (lines[i] == "" || lines[i][0] == '#') continue; if (sscanf(lines[i], "%s %s", svc, path) != 2) { log("load_services: error in services file, line " + (i + 1) + "\n"); continue; } service[svc] = path; }} voidcreate_listen_socket(){ int error; listen_fd = socket_create(STREAM, "read_callback", "close_callback"); if (listen_fd < 0) { log("create_listen_socket: socket_create: " + socket_error(listen_fd) + "\n"); return; } error = socket_bind(listen_fd, (int)DNS_MASTER->get_mudresource(mud_nname(), "inetd")); if (error != EESUCCESS) { socket_close(listen_fd); log("create_listen_socket: socket_bind: " + socket_error(listen_fd) + "\n"); return; } error = socket_listen(listen_fd, "read_callback"); if (error != EESUCCESS) { socket_close(listen_fd); log("create_listen_socket: socket_listen: " + socket_error(listen_fd) + "\n"); return; }} voidclose_socket(int id){ if (!sockets[id] || ((previous_object() != this_object()) && (previous_object() != sockets[id]["owner"]))) { log("close_socket: security violation on socket id " + id + "\n"); return 0; } sockets[id]["closing"] = 1; possible_close(id);} voidclose_callback(int fd){ if (fd == listen_fd) { log("close_callback: shutdown on listen fd " + fd + "\n"); return; } if(sockets[fd]["owner"]) call_other(sockets[fd]["owner"], sockets[fd]["close_callback"], fd); map_delete(sockets, fd); // nuke this puppy} voidwrite_callback(int id){ sockets[id]["wcb_pending"] = 0; if (strlen(sockets[id]["outgoing"]) > 0) { string send; send = sockets[id]["outgoing"]; sockets[id]["outgoing"] = ""; this_object()->write_socket(id, send); possible_close(id); }} void read_callback(int fd, string msg){ string tmp1, tmp2; if (fd == listen_fd) { int new_fd; new_fd = socket_accept(fd, "read_callback", "write_callback"); if (new_fd < 0) { log("read_callback: socket_accept: " + socket_error(new_fd) + "\n"); return; } sockets[new_fd] = allocate_mapping(8); sockets[new_fd]["fd"] = new_fd; sockets[new_fd]["incoming"] = ""; sockets[new_fd]["outgoing"] = ""; sockets[new_fd]["read_callback"] = "read_callback"; sockets[new_fd]["close_callback"] = "close_callback"; sockets[new_fd]["service_callback"] = "service_callback"; sockets[new_fd]["service_status"] = AWAITING_SERVICE; write_socket(new_fd, "SERVICE?\n"); return; } if (!sockets[fd]) { log("read_callback: callback on unknown socket fd " + fd + "\n"); return; } sockets[fd]["incoming"] += msg; while (sscanf(sockets[fd]["incoming"], "%s\n%s", tmp1, tmp2) == 2) { sockets[fd]["incoming"] = tmp1 + "\n"; process_incoming(fd); sockets[fd]["incoming"] = tmp2; }} intcreate_socket(string dest){ int fd, error; fd = socket_create(STREAM, "read_callback", "close_callback"); if (fd < 0) { log("create_socket: socket_create: " + socket_error(fd) + "\n"); return -1; } error = socket_connect(fd, dest, "read_callback", "write_callback"); if (error != EESUCCESS) { socket_close(fd); log("create_socket: socket_connect: " + socket_error(error) + "\n"); return -1; } sockets[fd] = allocate_mapping(8); sockets[fd]["fd"] = fd; sockets[fd]["incoming"] = ""; sockets[fd]["owner"] = previous_object(); sockets[fd]["outgoing"] = ""; sockets[fd]["read_callback"] = "read_callback"; sockets[fd]["close_callback"] = "close_callback"; sockets[fd]["service_callback"] = "service_callback"; return fd;} intopen_service(string mud, string svc, string *parms){ int id; string address; address = INETD_PORT(mud); if (!address) { return -1; } id = create_socket(address); if (id < 0) { return id; } sockets[id]["service_status"] = AWAITING_CONNECT_ACK; sockets[id]["service_desired"] = svc + (parms ? (" " + implode(parms, " ")) : ""); return id;} void process_incoming(int fd){ object ob; int error, l; string msg, svc, *parms; msg = this_object()->read_socket(fd); switch (sockets[fd]["service_status"]) { case AWAITING_CONNECT_ACK: if (msg == "SERVICE?\n") { this_object()->write_socket(fd, sockets[fd]["service_desired"] + "\n"); sockets[fd]["service_status"] = AWAITING_DATA; call_other(sockets[fd]["owner"], sockets[fd]["service_callback"], fd); return; } break; case AWAITING_DATA: call_other(sockets[fd]["owner"], sockets[fd]["read_callback"], fd, msg); break; case AWAITING_SERVICE: svc = msg[0..-2]; parms = explode(svc, " "); if (!service[parms[0]]) { write_socket(fd, "SERVICE NOT AVAILABLE\n"); close_socket(fd); } svc = parms[0]; service[svc]->dummy(); sockets[fd]["owner"] = find_object(service[svc]); sockets[fd]["service_status"] = AWAITING_DATA; service[svc]->service_request(fd, parms[1..sizeof(parms)-1]); break; default : break; }}voidcreate(){ seteuid(getuid(this_object())); sockets = ([]); load_services(); create_listen_socket();}/* client: To initiate, use INETD->open_service(string mudname, string servicename, string *parms) The id of the socket assigned to your service request will be returned, or -1 for failure. the calling object is used as the owner. The function service_callback(id) will be called in the owner when the service is open and ready for data transfer. server: service_request(int id, string *parms) will be called in the server object of the appropriate service whenever a request for that service is made. The server object is set as owner. both: INETD->write_socket(int id, string msg) sends text out the socket the function read_callback(int id, string msg) will be called in the owner when data is received. The function close_callback(id) will be called in the owner if the socket closes from the other end, INETD->close_socket(int id) can be used to close it from our end*/mapping query_sockets(){ if(member_group(geteuid(previous_object()),"admin")) return sockets; return 0;}mapping query_service(){ if(member_group(geteuid(previous_object()),"admin")) return service; return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?