/* /daemon/mcp_d.c * from Intermare libs */ #include <std.h> #include <daemons.h> #include <security.h> #include <network.h> #include <socket.h> #include "mcp_d.h" inherit DAEMON; #define PORT_MCP (query_host_port() - 4) #define MAX_ONE_WRITE 3072 #define VALID_INTERMARES ([ "199.199.122.10": ({ "tna", "3996" }), \ "134.130.76.1": ({ "teu", "4996" }) ]) static private int __SocketMCP; static private mapping __Sockets; static private mapping __ValidHosts; void create() { daemon::create(); set_no_clean(1); __Sockets = ([]); __ValidHosts = VALID_INTERMARES; call_out("setup", 2); call_out("clean_sockets", 180); } static void setup() { if((__SocketMCP=socket_create(STREAM,"read_callback","close_callback"))<0){ log_file("inter_copy", "Failed to create socket.\n"); return; } if(socket_bind(__SocketMCP, PORT_MCP) < 0) { socket_close(__SocketMCP); log_file("inter_copy", "Failed to bind port to socket.\n"); return; } if(socket_listen(__SocketMCP, "listen_callback") < 0) { socket_close(__SocketMCP); log_file("inter_copy", "Failed to listen to socket.\n"); } } void listen_callback(int fd) { int New; string tmp; if((New = socket_accept(fd, "read_callback", "write_callback")) < 0) return; if(!__Sockets[New]) { sscanf(socket_address(New), "%s %*s", tmp); if (member_array(tmp,keys(__ValidHosts)) == -1) { socket_close(New); log_file("inter_copy", "Illegal connection attempt from "+tmp+".\n"); } else __Sockets[New] = ([ "address": tmp, "time": time() ]); } } void write_callback(int fd) { int i, pos; string str, file; if (str = __Sockets[fd]["pos"]) { pos = to_int(str); file = __Sockets[fd]["file"]; if (pos == 0) { i = file_size(file); if (i > 0) { if (i >= MAX_ONE_WRITE) { str = read_file(file,1,49); socket_write(fd, "store "+file+"\n"+str); __Sockets[fd]["pos"]="50"; __Sockets[fd]["file"]=file; map_delete(__Sockets[fd],"write_callback"); if (find_call_out("write_tick") == -1) call_out("write_tick",1); } else { str = read_file(file); socket_write(fd, "store "+file+"\n"+str+"****EOT****\n"); close_connection(fd); } } else { close_connection(fd); } } } } void read_callback(int fd, string str) { string *lines; string cmd, args; int eof, i, j; if(str && str != "") { str = replace_string(str, "\r", ""); if (str == "\n" || str == "") lines = ({ "" }); else lines = explode(str,"\n"); if (__Sockets[fd]["store"]) { eof = 0; if ((i = sizeof(lines)) > 0) { if (lines[i-1] == "****EOT****") { eof = 1; i--; if (i) for (j=0;j<i;j++) write_file(__Sockets[fd]["store"],lines[j]+"\n"); } else write_file(__Sockets[fd]["store"],str); } if (eof) close_connection(fd); return; } sscanf(lines[0], "%s %s", cmd, args); switch(lower_case(cmd)) { case "retrieve": retrieve_file(fd, args); return; case "store": store_file(fd, args, lines); return; // add here default: close_connection(fd); return; } } } void close_callback(int fd) { socket_close(fd); if(fd == __SocketMCP) this_object()->remove(); } void close_connection(int fd) { map_delete(__Sockets, fd); socket_close(fd); } static void clean_sockets() { int *cles; int i; i = sizeof(cles = keys(__Sockets)); while(i--) if(time() - __Sockets[cles[i]]["time"] > 180) close_connection(cles[i]); call_out("clean_sockets", 180); } void remove() { if(previous_object() != this_object()) return 0; socket_close(__SocketMCP); destruct(this_object()); // return daemon::remove(); } void write_tick() { int i, fd, f, pos; string str; f = 0; i = sizeof(__Sockets); while (i--) { fd = keys(__Sockets)[i]; if (__Sockets[fd]["write_callback"]) continue; if (str = __Sockets[fd]["pos"]) { pos = to_int(str); str = read_file(__Sockets[fd]["file"],pos,50); if (str) { socket_write(fd, str); __Sockets[fd]["pos"]=sprintf("%d",pos+50); __Sockets[fd]["time"]=time(); f++; } else { socket_write(fd,"****EOT****\n"); close_connection(fd); } } } if (f) call_out("write_tick",1); } static private void retrieve_file(int fd, string file) { string str; int i; if (strlen(file) < 5 || file[0..4] != "/ftp/") { log_file("inter_copy", __Sockets[fd]["address"]+" attempted to retrieve: "+file+".\n"); close_connection(fd); return; } log_file("inter_copy", __Sockets[fd]["address"]+" retrieved: "+file+".\n"); i = file_size(file); if (i > 0) { if (i >= MAX_ONE_WRITE) { str = read_file(file,1,49); socket_write(fd, "store "+file+"\n"); socket_write(fd, str); __Sockets[fd]["pos"]="50"; __Sockets[fd]["file"]=file; if (find_call_out("write_tick") == -1) call_out("write_tick",1); } else { str = read_file(file); socket_write(fd, "store "+file+"\n"); socket_write(fd, str); socket_write(fd,"****EOT****\n"); close_connection(fd); } } } static private void store_file(int fd, string file, string *lines) { int i, j, eof; if (strlen(file) < 5 || file[0..4] != "/ftp/") { log_file("inter_copy", __Sockets[fd]["address"]+" attempted to store: "+file+".\n"); close_connection(fd); return; } log_file("inter_copy", __Sockets[fd]["address"]+" stored: "+file+".\n"); rm(file); eof = 0; if ((i = sizeof(lines)) > 1) { if (lines[i-1] == "****EOT****") { eof = 1; i--; } for (j=1;j<i;j++) write_file(file,lines[j]+"\n"); } if (!eof) __Sockets[fd]["store"]=file; } static private void do_send(string file,string dest) { int fd; if (strlen(file) < 5 || file[0..4] != "/ftp/") { log_file("inter_copy", "Someone attempted to send: "+file+".\n"); return; } log_file("inter_copy", "Someone send: "+file+" to "+dest+".\n"); if((fd=socket_create(STREAM,"read_callback","close_callback"))<0){ log_file("inter_copy", "Failed to create send socket.\n"); return; } __Sockets[fd] = ([ "address": explode(dest," ")[0], "time": time(), "pos": "0", "file": file, "write_callback": 1, ]); if(socket_connect(fd, dest, "read_callback", "write_callback") < 0) { socket_close(fd); map_delete(__Sockets, fd); log_file("inter_copy", "Failed to connect send socket.\n"); } } void send_file(string file, string mud) { int i; if (!mud || !file) return; for (i=0; i<sizeof(__ValidHosts); i++) { if (__ValidHosts[keys(__ValidHosts)[i]][0] == mud) { do_send(file,keys(__ValidHosts)[i]+" "+ __ValidHosts[keys(__ValidHosts)[i]][1]); break; } } }