int ftp_get_filesize(int sock, const char * remotename) { int size = 0; char buf[2000]; char file[500]; char * ptr; int fd, rc, tot; int i; strcpy(buf, remotename); ptr = strrchr(buf, '/'); if (!*ptr) return -1; *ptr = '\0'; strcpy(file, ptr+1); if ((rc = ftp_command(sock, "CWD", buf))) { return -1; } fd = ftp_data_command(sock, "LIST", file); if (fd <= 0) { close(sock); return -1; } ptr = buf; while ((tot = read(fd, ptr, sizeof(buf) - (ptr - buf) - 1)) != 0) ptr += tot; *ptr = '\0'; close(fd); if (!(ptr = strstr(buf, file))) { log_message("FTP/get_filesize: Bad mood, directory does not contain searched file (%s)", file); if (ftp_end_data_command(sock)) close(sock); return -1; } for (i=0; i<4; i++) { while (*ptr && *ptr != ' ') ptr--; while (*ptr && *ptr == ' ') ptr--; } while (*ptr && *ptr != ' ') ptr--; if (ptr) size = charstar_to_int(ptr+1); else size = 0; if (ftp_end_data_command(sock)) { close(sock); return -1; } return size; }
static int _http_download_file(const char * hostname, const char * remotename, int * size, const char * proxyprotocol, const char * proxyname, const char * proxyport, int recursion) { char * buf; char headers[4096]; char * nextChar = headers; int statusCode; struct in_addr serverAddress; struct pollfd polls; int sock; int rc; union { struct sockaddr_in in; struct sockaddr sa; } destPort; const char * header_content_length = "Content-Length: "; const char * header_location = "Location: http://"; const char * http_server_name; int http_server_port; if (proxyprotocol) { http_server_name = proxyname; http_server_port = atoi(proxyport); } else { http_server_name = hostname; http_server_port = 80; } log_message("HTTP: connecting to server %s:%i (%s)", http_server_name, http_server_port, proxyprotocol ? "proxy" : "no proxy"); if ((rc = get_host_address(http_server_name, &serverAddress))) return rc; sock = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (sock < 0) { return FTPERR_FAILED_CONNECT; } destPort.in.sin_family = AF_INET; destPort.in.sin_port = htons(http_server_port); destPort.in.sin_addr = serverAddress; if (connect(sock, &destPort.sa, sizeof(destPort.in))) { close(sock); return FTPERR_FAILED_CONNECT; } if (proxyprotocol) asprintf(&buf, "GET %s://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n", proxyprotocol, hostname, remotename, hostname); else asprintf(&buf, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", remotename, hostname); write(sock, buf, strlen(buf)); /* This is fun; read the response a character at a time until we: 1) Get our first \r\n; which lets us check the return code 2) Get a \r\n\r\n, which means we're done */ *nextChar = '\0'; statusCode = 0; while (!strstr(headers, "\r\n\r\n")) { polls.fd = sock; polls.events = POLLIN; rc = poll(&polls, 1, TIMEOUT_SECS*1000); if (rc == 0) { close(sock); return FTPERR_SERVER_TIMEOUT; } else if (rc < 0) { close(sock); return FTPERR_SERVER_IO_ERROR; } if (read(sock, nextChar, 1) != 1) { close(sock); return FTPERR_SERVER_IO_ERROR; } nextChar++; *nextChar = '\0'; if (nextChar - headers == sizeof(headers)) { close(sock); return FTPERR_SERVER_IO_ERROR; } if (!statusCode && strstr(headers, "\r\n")) { char * start, * end; start = headers; while (!isspace(*start) && *start) start++; if (!*start) { close(sock); return FTPERR_SERVER_IO_ERROR; } start++; end = start; while (!isspace(*end) && *end) end++; if (!*end) { close(sock); return FTPERR_SERVER_IO_ERROR; } *end = '\0'; log_message("HTTP: server response '%s'", start); if (streq(start, "404")) { close(sock); return FTPERR_FILE_NOT_FOUND; } else if (streq(start, "302")) { log_message("HTTP: found, but document has moved"); statusCode = 302; } else if (streq(start, "200")) { statusCode = 200; } else { close(sock); return FTPERR_BAD_SERVER_RESPONSE; } *end = ' '; } } if (statusCode == 302) { if (recursion >= HTTP_MAX_RECURSION) { log_message("HTTP: too many levels of recursion, aborting"); close(sock); return FTPERR_UNKNOWN; } if ((buf = strstr(headers, header_location))) { char * found_host; char *found_file; found_host = buf + strlen(header_location); if ((found_file = index(found_host, '/'))) { if ((buf = index(found_file, '\r'))) { buf[0] = '\0'; remotename = strdup(found_file); found_file[0] = '\0'; hostname = strdup(found_host); log_message("HTTP: redirected to new host \"%s\" and file \"%s\"", hostname, remotename); } } } /* * don't fail if new URL can't be parsed, * asking the same URL may work if the DNS server are doing round-robin */ return _http_download_file(hostname, remotename, size, proxyprotocol, proxyname, proxyport, recursion + 1); } if ((buf = strstr(headers, header_content_length))) *size = charstar_to_int(buf + strlen(header_content_length)); else *size = 0; return sock; }
/* true return value indicates that connection must be closed */ int process_msg(int fd, char* msg) { int client_proto_major; int client_proto_minor; char * args; char * ptr, * ptr2; char * msg_orig; /* check for leading protocol tag */ if (!str_begins_static_str(msg, "FB/") || strlen(msg) < 8) { // 8 stands for "FB/M.m f"(oo) send_line_log(fd, fl_line_unrecognized, msg); return 1; } /* check if client protocol is compatible; for simplicity, we don't support client protocol more recent * than server protocol, we suppose that our servers are upgraded when a new release appears (but of * course client protocol older is supported within the major protocol) */ client_proto_major = charstar_to_int(msg + 3); client_proto_minor = charstar_to_int(msg + 5); if (client_proto_major != proto_major || client_proto_minor > proto_minor) { send_line_log(fd, fl_proto_mismatch, msg); return 1; } if (remote_proto_minor[fd] == -1) remote_proto_minor[fd] = client_proto_minor; msg_orig = strdup(msg); /* after protocol, first word is command, then possible args */ current_command = msg + 7; // 7 stands for "FB/M.m " if ((ptr = strchr(current_command, ' '))) { *ptr = '\0'; args = current_command + strlen(current_command) + 1; } else args = NULL; if (streq(current_command, "PING")) { send_line_log(fd, ok_pong, msg_orig); } else if (streq(current_command, "NICK")) { if (!args) { send_line_log(fd, wn_missing_arguments, msg_orig); } else { if ((ptr = strchr(args, ' '))) *ptr = '\0'; if (strlen(args) > 10) args[10] = '\0'; if (!is_nick_ok(args)) { send_line_log(fd, wn_nick_invalid, msg_orig); } else { if (nick[fd] != NULL) { free(nick[fd]); } nick[fd] = strdup(args); calculate_list_games(); send_ok(fd, msg_orig); } } } else if (streq(current_command, "GEOLOC")) { if (!args) { send_line_log(fd, wn_missing_arguments, msg_orig); } else { if ((ptr = strchr(args, ' '))) *ptr = '\0'; if (strlen(args) > 13) // sign, 4 digits, dot, colon, sign, 4 digits, dot args[13] = '\0'; if (geoloc[fd] != NULL) { free(geoloc[fd]); } geoloc[fd] = strdup(args); calculate_list_games(); send_ok(fd, msg_orig); } } else if (streq(current_command, "CREATE")) { if (!args) { send_line_log(fd, wn_missing_arguments, msg_orig); } else { if ((ptr = strchr(args, ' '))) *ptr = '\0'; if (strlen(args) > 10) args[10] = '\0'; if (!is_nick_ok(args)) { send_line_log(fd, wn_nick_invalid, msg_orig); } else if (!nick_available(args)) { send_line_log(fd, wn_nick_in_use, msg_orig); } else if (already_in_game(fd)) { send_line_log(fd, wn_already_in_game, msg_orig); } else if (games_open == 16) { // FB client can display 16 max send_line_log(fd, wn_max_open_games, msg_orig); } else { create_game(fd, strdup(args)); send_ok(fd, msg_orig); } } } else if (streq(current_command, "JOIN")) { if (!args || !(ptr = strchr(args, ' '))) { send_line_log(fd, wn_missing_arguments, msg_orig); } else { struct game * g; char* nick = ptr + 1; *ptr = '\0'; if ((ptr2 = strchr(ptr, ' '))) *ptr2 = '\0'; if (strlen(nick) > 10) nick[10] = '\0'; if (!is_nick_ok(nick)) { send_line_log(fd, wn_nick_invalid, msg_orig); } else if (!nick_available(nick)) { send_line_log(fd, wn_nick_in_use, msg_orig); } else if (already_in_game(fd)) { send_line_log(fd, wn_already_in_game, msg_orig); } else if (!(g = find_game_by_nick(args))) { send_line_log(fd, wn_no_such_game, msg_orig); } else { if (add_player(g, fd, strdup(nick))) send_ok(fd, msg_orig); else send_line_log(fd, wn_game_full, msg_orig); } } } else if (streq(current_command, "KICK")) { if (!args) { send_line_log(fd, wn_missing_arguments, msg_orig); } else { if ((ptr = strchr(args, ' '))) *ptr = '\0'; if (strlen(args) > 10) args[10] = '\0'; if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { struct game * g = find_game_by_fd(fd); if (g->players_conn[0] != fd) { send_line_log(fd, wn_not_creator, msg_orig); } else { kick_player(fd, g, args); } } } } else if (streq(current_command, "PART")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { player_part_game(fd); send_ok(fd, msg_orig); } } else if (streq(current_command, "LIST")) { send_line_log(fd, list_games_str, msg_orig); } else if (streq(current_command, "STATUS")) { // 1.0 command if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { status(fd, msg_orig); } } else if (streq(current_command, "STATUSGEO")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { status_geo(fd, msg_orig); } } else if (streq(current_command, "PROTOCOL_LEVEL")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { protocol_level(fd, msg_orig); } } else if (streq(current_command, "TALK")) { if (!args) { send_line_log(fd, wn_missing_arguments, msg_orig); } else { talk(fd, args); } } else if (streq(current_command, "START")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { start_game(fd); } } else if (streq(current_command, "CLOSE")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { close_game(fd); } } else if (streq(current_command, "SETOPTIONS")) { if (!args) { send_line_log(fd, wn_missing_arguments, msg_orig); } else if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { setoptions(fd, args); } } else if (streq(current_command, "LEADER_CHECK_GAME_START")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { leader_check_game_start(fd); } } else if (streq(current_command, "OK_GAME_START")) { if (!already_in_game(fd)) { send_line_log(fd, wn_not_in_game, msg_orig); } else { ok_start_game(fd); } } else if (streq(current_command, "ADMIN_REREAD")) { if (!admin_authorized[fd]) { send_line_log(fd, wn_denied, msg_orig); } else { reread(); send_ok(fd, "ADMIN_REREAD"); } } else { send_line_log(fd, wn_unknown_command, msg); } free(msg_orig); current_command = NULL; return 0; }