#define tell(x) if(find_living("inspiral")) tell_object(find_living("inspiral"), x + "\n") /* This *should* work. I wont garantee it. I have not had a chance to test it. The link from australia to the rest of the world is very sick and I can't connect to any muds :( Share and enjoy, David. [DDT] Pink fish forever. PS I will send you a replacement for out_finger.c too. */ /* * The wholely non useful inetd written by pinkfish@discworld. * Blue. */ #include "socket.h" /* * inetd type means it all runs through ident's bound socket. * It does all sort of useful and hairy things this way. */ #define VALID_TYPE ({ "mud", "tcp", "udp", "inetd" }) #define INETD_TYPE 3 #define CONFIG "/adm/net/config/" #define NAMESERVER "/adm/net/nameserver" /* This is indexed by file descriptor */ mapping services, to_go, my_valid, close_it; string damn_you; int my_socket; void load_config(string str); void close_callback(int fd); void create() { seteuid(getuid()); services = ([ ]); to_go = ([ ]); my_valid = ([ ]); close_it = ([ ]); load_config(CONFIG+"inetd"); } /* create() */ /* Make sure our inetd server is running */ void connect_inetd() { if (damn_you) /* Already up */ return ; my_socket = socket_create(STREAM, "inetd_read", "close_callback"); if (my_socket < 0) { log_file("INETD", "Failed to find service create socket "+ socket_error(my_socket)+".\n"); return ; } NAMESERVER->lookup_service("inetd", "tabor", "finish_lookup"); } /* connect_inetd() */ void finish_lookup(string name, string host, int port) { int ret; if (!port) return ; ret = socket_bind(my_socket, port); if (ret < 0) { socket_close(my_socket); my_socket = 0; tell("FAIL!\n"); log_file("INETD", "Failed to bind socket for "+name+ "-"+socket_error(ret)+".\n"); return ; } /* tell("SS with my_socket = " + dump_variable(my_socket)); tell("SUCCESS!\n"); tell("setting damn_you"); */ damn_you = "SUCCESS"; ret = socket_listen(my_socket, "inetd_connect"); if (ret < 0) { socket_close(my_socket); my_socket = 0; log_file("INETD", "Failed to listen socket for "+name+ "-"+socket_error(ret)+".\n"); return ; } } /* finish_lookup() */ void load_config(string name) { string data, str, file, *lines; int i, type; data = read_file(name); if (!data) return ; data = replace_string(data, "\t", " "); data = replace_string(data, " ", " "); data = replace_string(data, " ", " "); lines = explode(data, "\n"); for (i=0;i<sizeof(lines);i++) { while (strlen(lines[i]) && lines[i][0] == ' ') lines[i] = lines[i][1..1000]; if (!strlen(lines[i]) || lines[i][0] == '#') continue; if (sscanf(lines[i], "%s %s %s", name, str, file) == 3) { if ((type = member_array(str, VALID_TYPE)) == -1) continue; if (type == INETD_TYPE) { my_valid[name] = file; connect_inetd(); } else NAMESERVER->lookup_service(name, "tabor", "found_service", ({ type, file })); } } } /* load_config() */ void found_service(string name, string host, int port, mixed args) { int fd, ret; /* Failed :( */ if (!port) { log_file("INETD", "Failed to find service "+name+".\n"); return ; } /* Ok... we have a service... so set ourselves up a look thingy */ fd = socket_create(args[0], "read_callback", "close_callback"); if (fd < 0) { log_file("INETD", "Failed to create socket for "+name+ "-"+socket_error(fd)+".\n"); return ; } ret = socket_bind(fd, port); if (ret < 0) { socket_close(fd); log_file("INETD", "Failed to bind socket for "+name+ "-"+socket_error(ret)+".\n"); return ; } if (args[0] != DATAGRAM) { ret = socket_listen(fd, "listen_callback"); if (ret < 0) { socket_close(fd); log_file("INETD", "Failed to listen socket for "+name+ "-"+socket_error(ret)+".\n"); return ; } } /* Ok... tis setup. Bing! */ /* Do we need to remember what port we are on? Nahhh... */ services[fd] = args[1]; } /* found_service() */ void read_callback(int fd, string str) { string file; file = services[fd]; if (!file) { socket_close(fd); return ; } file->read_callback(fd, str); } /* read_callback() */ void write_callback(int fd) { int last, i; if (!to_go[fd]) to_go[fd] = 1; if (!pointerp(to_go[fd])) { services[fd]->write_callback(fd); return ; } while (sizeof(to_go[fd]) && (last = socket_write(fd, to_go[fd][0])) >= 0) to_go[fd] = to_go[fd][1..100]; if (!sizeof(to_go[fd])) { to_go[fd] = (last >= 0); if (to_go[fd]) { if (close_it[fd]) { close_callback(fd); map_delete(close_it, fd); } else services[fd]->write_callback(fd); } } } /* write_callback() */ void write_fd(int fd, mixed mess) { int bing; /* Security violation... */ if (previous_object() != this_object() && previous_object() != services[fd] && file_name(previous_object()) != services[fd]) return ; if (!pointerp(to_go[fd])) { /* * If in here there is nothing in the queue already. so we assume we can * send down the link. */ to_go[fd] = ({ mess }); bing = 1; } else to_go[fd] += ({ mess }); if (bing) write_callback(fd); } /* write_fd() */ /* * This sets the close_it flag or closes it immediately if there is * nothing to go and we have the correct flags. */ void close_fd(int fd) { int bing; if (previous_object() != this_object() && previous_object() != services[fd] && file_name(previous_object()) != services[fd]) return ; bing = intp(to_go[fd]) && to_go[fd]; if (bing) { close_callback(fd); } else close_it[fd] = 1; } /* close_fd() */ void close_callback(int fd) { if (!services[fd]) return ; services[fd]->close_callback(fd); map_delete(services, fd); map_delete(my_valid, fd); /* Just to make sure... */ socket_close(fd); } /* close_callback() */ void listen_callback(int fd) { int new_fd; if ((new_fd = socket_accept(fd, "read_callback", "write_callback")) < 0) { log_file("INETD", "Failed to accept a connection "+ "-"+socket_error(new_fd)+".\n"); return ; } services[new_fd] = services[fd]; /* whats all this then? */ call_out("close_callback", 5*60*60, new_fd); to_go[new_fd] = 1; } /* listen_callback() */ void inetd_connect(int fd) { int new_fd; if ((new_fd = socket_accept(fd, "inetd_read", "inetd_write")) < 0) { log_file("INETD", "Failed to accept a connection "+ "-"+socket_error(new_fd)+".\n"); return ; } services[new_fd] = "request"; socket_write(new_fd, "SERVICE?\n"); to_go[new_fd] = 1; call_out("close_callback", 5*60*60, new_fd); } /* inetd_connect() */ void inetd_read(int fd, string mess) { string *bits; if (!services[fd]) { socket_close(fd); return ; } switch (services[fd]) { case "waiting" : /* Should be asking us for a service... */ if (!my_valid[fd]) { socket_close(fd); return ; } if (mess == "SERVICE?\n") { /* They are... */ /* * The old one doesnt use a response code.... so... We won't * either for now. services[fd] = "response"; */ /* tell(dump_variable(my_valid[fd])); */ if (my_valid[fd][2]) socket_write(fd, my_valid[fd][0]+" "+my_valid[fd][2]+"\n"); else socket_write(fd, my_valid[fd][0]+"\n"); services[fd] = my_valid[fd][1]; map_delete(my_valid, fd); services[fd]->connected(fd); } return ; case "response" : if (mess == "YES!\n") { /* Ok! Bings are us */ if (!my_valid[fd]) { socket_close(fd); return ; } services[fd] = my_valid[fd][1]; map_delete(my_valid, fd); services[fd]->connected(fd); } else { socket_close(fd); if (my_valid[fd]) my_valid[fd][1]->failed("unknown service"); map_delete(my_valid, fd); return ; } return ; case "request" : mess = replace_string(mess, "\n", " "); mess = replace_string(mess, "\n", " "); bits = explode(mess, " "); /* mess = mess[0..strlen(mess)-2]; /* Strip the \n */ mess = bits[0]; if (!my_valid[mess]) { /* Invalid service... */ socket_write(fd, "UNKNOWN SERVICE\n"); socket_close(fd); return ; } /* Don't need the yes string. socket_write(fd, "YES!\n"); */ services[fd] = my_valid[mess]; services[fd]->connected(fd); if (sizeof(bits) > 1) { read_callback(fd, implode(bits[1..1000], "\n")); } return ; default : read_callback(fd, mess); return ; } } /* inetd_read() */ void inetd_write(int fd) { if (!services[fd]) { socket_close(fd); return ; } switch (services[fd]) { case "response" : case "waiting" : case "request" : to_go[fd] = 1; return ; default : write_callback(fd); return ; } } /* inetd_write() */ /* * Sends a message off to the destination service, with closeing * and opening of sockets etc done all for you. * Maybe useful, dubious. */ void datagram_message(string name, string dest, string mess) { NAMESERVER->lookup_service(name, dest, "finish_datagram_open", ({ previous_object(), name, mess })); } /* datagram_message() */ /* * The last paramater bing is used for compatability with an older * version of inetd. Please do not use this in any new daemons you * create. I consider it somewhat of a hack. This is also only * used in the INETD_TYPE case, not for streams or mud connections. */ void open_to_service(string name, int type, string dest, string bing) { if (type == DATAGRAM) { /* * What we do here is resolv a named [port thingy and return that to * the calling object... */ previous_object()->failed("unsupported type", name, name, dest); return ; } if (type == INETD_TYPE) { NAMESERVER->lookup_service("inetd", dest, "finish_inet_open", ({ previous_object(), name, bing })); return ; } /* Else.... */ NAMESERVER->lookup_service(name, dest, "finish_open", ({ previous_object(), type })); } /* open_to_service() */ void finish_open(string name, string host, int port, mixed *args) { int new_fd, ret; if (!args[0]) return ; if (!port) { args[0]->failed("lookup", name, args[1], host); return ; } new_fd = socket_create(args[1], "read_callback", "close_callback"); if (new_fd < 0) { args[0]->failed("socket_create", name, args[1], host, new_fd); return ; } ret = socket_connect(new_fd, host+" "+port, "read_callback", "write_callback"); if (ret < 0) { args[0]->failed("socket_connect", name, args[1], host, new_fd); return ; } call_out("close_callback", 5*60*60, new_fd); services[new_fd] = file_name(args[0]); args[0]->connected(new_fd); } /* finish_open() */ void finish_inet_open(string name, string host, int port, mixed *args) { int new_fd, ret; if (!args[0]) return ; if (!port) { args[0]->failed("lookup", name, args[1], host); return ; } new_fd = socket_create(STREAM, "inetd_read", "close_callback"); if (new_fd < 0) { args[0]->failed("socket_create", name, args[1], host, new_fd); return ; } ret = socket_connect(new_fd, host+" "+port, "inetd_read", "inetd_write"); if (ret < 0) { args[0]->failed("socket_connect", name, args[1], host, new_fd); return ; } call_out("close_callback", 5*60*60, new_fd); my_valid[new_fd] = ({ args[1], file_name(args[0]), args[2] }); services[new_fd] = "waiting"; } /* finish_inet_open() */ void finish_datagram_open(string name, string host, int port, mixed *args) { int s; if (!port) { if (args[0]) args[0]->failed("lookup", name, args[1], host); return ; } s = socket_create(DATAGRAM, "blurble"); if (s < 0) { if (args[0]) { args[0]->failed("socket_create", name, args[1], host); } return ; } if (socket_write(s, args[2], host+" "+port) < 0) { /* Tarnation... */ if (args[0]) args[0]->failed("socket_write", name, args[1], host); } socket_close(s); } /* finish_datagram_open() */