static int handle_logtime_config(struct nlmsghdr *nl_hdr, struct request_hdr *nat64_hdr, struct request_logtime *request) { #ifdef BENCHMARK struct nl_buffer *buffer; int error; switch (nat64_hdr->operation) { case OP_DISPLAY: log_debug("Sending logs time to userspace."); buffer = nlbuffer_create(nl_socket, nl_hdr); if (!buffer) return respond_error(nl_hdr, -ENOMEM); error = logtime_iterate_and_delete(request->l3_proto, request->l4_proto, logtime_entry_to_userspace, buffer); error = (error >= 0) ? nlbuffer_close(buffer, error) : respond_error(nl_hdr, error); kfree(buffer); return error; default: log_err("Unknown operation: %d", nat64_hdr->operation); return respond_error(nl_hdr, -EINVAL); } #else log_err("Benchmark was not enabled during compilation."); return -EINVAL; #endif }
static int routeQuery(ROUTER *instance, void *session, GWBUF *queue) { WEB_SESSION *wsession = (WEB_SESSION *)session; char *ptr; int i, found = 0; char *url; if ((url = gwbuf_get_property(queue, "URL")) == NULL) { respond_error(wsession, 404, "No URL available"); } ptr = strrchr(url, '/'); if (ptr) ptr++; else ptr = url; for (i = 0; pages[i].page; i++) { if (!strcmp(ptr, pages[i].page)) { (pages[i].fcn)(wsession); found = 1; } } if (!found) respond_error(wsession, 404, "Unrecognised URL received"); gwbuf_free(queue); return 0; }
static int handle_session_config(struct nlmsghdr *nl_hdr, struct request_hdr *nat64_hdr, struct request_session *request) { __u64 count; int error; if (nat64_is_stateless()) { log_err("SIIT doesn't have session tables."); return -EINVAL; } switch (nat64_hdr->operation) { case OP_DISPLAY: return handle_session_display(nl_hdr, request); case OP_COUNT: log_debug("Returning session count."); error = sessiondb_count(request->l4_proto, &count); if (error) return respond_error(nl_hdr, error); return respond_setcfg(nl_hdr, &count, sizeof(count)); default: log_err("Unknown operation: %d", nat64_hdr->operation); return respond_error(nl_hdr, -EINVAL); } }
static int handle_pool6_config(struct nlmsghdr *nl_hdr, struct request_hdr *jool_hdr, union request_pool6 *request) { __u64 count; int error; switch (jool_hdr->operation) { case OP_DISPLAY: return handle_pool6_display(nl_hdr, request); case OP_COUNT: log_debug("Returning IPv6 prefix count."); error = pool6_count(&count); if (error) return respond_error(nl_hdr, error); return respond_setcfg(nl_hdr, &count, sizeof(count)); case OP_ADD: case OP_UPDATE: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Adding a prefix to the IPv6 pool."); return respond_error(nl_hdr, pool6_add(&request->add.prefix)); case OP_REMOVE: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Removing a prefix from the IPv6 pool."); error = pool6_remove(&request->remove.prefix); if (error) return respond_error(nl_hdr, error); if (nat64_is_stateful() && !request->flush.quick) error = sessiondb_delete_by_prefix6(&request->remove.prefix); return respond_error(nl_hdr, error); case OP_FLUSH: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Flushing the IPv6 pool..."); error = pool6_flush(); if (error) return respond_error(nl_hdr, error); if (nat64_is_stateful() && !request->flush.quick) error = sessiondb_flush(); return respond_error(nl_hdr, error); default: log_err("Unknown operation: %d", jool_hdr->operation); return respond_error(nl_hdr, -EINVAL); } }
static int handle_rfc6791_config(struct nlmsghdr *nl_hdr, struct request_hdr *nat64_hdr, union request_pool4 *request) { __u64 count; int error; if (nat64_is_stateful()) { log_err("RFC 6791 does not apply to Stateful NAT64."); return -EINVAL; } switch (nat64_hdr->operation) { case OP_DISPLAY: return handle_pool6791_display(nl_hdr, request); case OP_COUNT: log_debug("Returning IPv4 address count."); error = rfc6791_count(&count); if (error) return respond_error(nl_hdr, error); return respond_setcfg(nl_hdr, &count, sizeof(count)); case OP_ADD: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Adding an address to the IPv4 pool."); return respond_error(nl_hdr, rfc6791_add(&request->add.addrs)); case OP_REMOVE: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Removing an address from the IPv4 pool."); error = rfc6791_remove(&request->remove.addrs); if (error) return respond_error(nl_hdr, error); return respond_error(nl_hdr, error); case OP_FLUSH: if (verify_superpriv()) { return respond_error(nl_hdr, -EPERM); } log_debug("Flushing the IPv4 pool..."); error = rfc6791_flush(); if (error) return respond_error(nl_hdr, error); return respond_error(nl_hdr, error); default: log_err("Unknown operation: %d", nat64_hdr->operation); return respond_error(nl_hdr, -EINVAL); } }
static int handle_pool4_add(struct nlmsghdr *nl_hdr, union request_pool4 *request) { if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Adding elements to the IPv4 pool."); return respond_error(nl_hdr, pool4db_add(request->add.mark, request->add.proto, &request->add.addrs, &request->add.ports)); }
/** * Gets called by "netlink_rcv_skb" when the userspace application wants to interact with us. * * @param skb packet received from userspace. * @param nlh message's metadata. * @return result status. */ static int handle_netlink_message(struct sk_buff *skb_in, struct nlmsghdr *nl_hdr) { struct request_hdr *jool_hdr; void *request; int error; if (nl_hdr->nlmsg_type != MSG_TYPE_JOOL) { log_debug("Expecting %#x but got %#x.", MSG_TYPE_JOOL, nl_hdr->nlmsg_type); return -EINVAL; } jool_hdr = NLMSG_DATA(nl_hdr); request = jool_hdr + 1; error = validate_version(jool_hdr); if (error) return respond_error(nl_hdr, error); switch (jool_hdr->mode) { case MODE_POOL6: return handle_pool6_config(nl_hdr, jool_hdr, request); break; case MODE_POOL4: return handle_pool4_config(nl_hdr, jool_hdr, request); break; case MODE_BIB: return handle_bib_config(nl_hdr, jool_hdr, request); break; case MODE_SESSION: return handle_session_config(nl_hdr, jool_hdr, request); break; case MODE_EAMT: return handle_eamt_config(nl_hdr, jool_hdr, request); break; case MODE_RFC6791: return handle_rfc6791_config(nl_hdr, jool_hdr, request); break; case MODE_BLACKLIST: return handle_blacklist_config(nl_hdr, jool_hdr, request); break; case MODE_LOGTIME: return handle_logtime_config(nl_hdr, jool_hdr, request); break; case MODE_GLOBAL: return handle_global_config(nl_hdr, jool_hdr, request); break; } log_err("Unknown configuration mode: %d", jool_hdr->mode); return respond_error(nl_hdr, -EINVAL); }
static int handle_global_config(struct nlmsghdr *nl_hdr, struct request_hdr *jool_hdr, union request_global *request) { struct global_config response = { .mtu_plateaus = NULL }; unsigned char *buffer; size_t buffer_len; bool disabled; int error; switch (jool_hdr->operation) { case OP_DISPLAY: log_debug("Returning 'Global' options."); error = config_clone(&response); if (error) goto end; disabled = xlat_is_nat64() ? pool6_is_empty() : (pool6_is_empty() && eamt_is_empty()); error = serialize_global_config(&response, disabled, &buffer, &buffer_len); if (error) goto end; error = respond_setcfg(nl_hdr, buffer, buffer_len); kfree(buffer); break; case OP_UPDATE: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Updating 'Global' options."); buffer = (unsigned char *) (request + 1); buffer_len = jool_hdr->length - sizeof(*jool_hdr) - sizeof(*request); error = handle_global_update(request->update.type, buffer_len, buffer); break; default: log_err("Unknown operation: %d", jool_hdr->operation); error = -EINVAL; } end: return respond_error(nl_hdr, error); }
static int handle_pool4_config(struct nlmsghdr *nl_hdr, struct request_hdr *jool_hdr, union request_pool4 *request) { struct response_pool4_count counters; if (xlat_is_siit()) { log_err("SIIT doesn't have pool4."); return -EINVAL; } switch (jool_hdr->operation) { case OP_DISPLAY: return handle_pool4_display(nl_hdr, request); case OP_COUNT: log_debug("Returning IPv4 pool counters."); pool4db_count(&counters.tables, &counters.samples, &counters.taddrs); return respond_setcfg(nl_hdr, &counters, sizeof(counters)); case OP_ADD: return handle_pool4_add(nl_hdr, request); case OP_REMOVE: return handle_pool4_rm(nl_hdr, request); case OP_FLUSH: return handle_pool4_flush(nl_hdr, request); default: log_err("Unknown operation: %d", jool_hdr->operation); return respond_error(nl_hdr, -EINVAL); } }
static int handle_blacklist_display(struct nlmsghdr *nl_hdr, union request_pool *request) { struct nl_buffer *buffer; struct ipv4_prefix *offset; int error; buffer = nlbuffer_create(nl_socket, nl_hdr); if (!buffer) return respond_error(nl_hdr, -ENOMEM); offset = request->display.offset_set ? &request->display.offset : NULL; error = blacklist_for_each(pool_to_usr, buffer, offset); error = (error >= 0) ? nlbuffer_close(buffer, error) : respond_error(nl_hdr, error); kfree(buffer); return error; }
static int handle_eamt_config(struct nlmsghdr *nl_hdr, struct request_hdr *jool_hdr, union request_eamt *request) { __u64 count; int error; if (xlat_is_nat64()) { log_err("Stateful NAT64 doesn't have an EAMT."); return -EINVAL; } switch (jool_hdr->operation) { case OP_DISPLAY: return handle_eamt_display(nl_hdr, request); case OP_COUNT: log_debug("Returning EAMT count."); error = eamt_count(&count); if (error) return respond_error(nl_hdr, error); return respond_setcfg(nl_hdr, &count, sizeof(count)); case OP_TEST: return handle_eamt_test(nl_hdr, request); case OP_ADD: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Adding EAMT entry."); return respond_error(nl_hdr, eamt_add(&request->add.prefix6, &request->add.prefix4, request->add.force)); case OP_REMOVE: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Removing EAMT entry."); return respond_error(nl_hdr, eamt_rm( request->rm.prefix6_set ? &request->rm.prefix6 : NULL, request->rm.prefix4_set ? &request->rm.prefix4 : NULL)); case OP_FLUSH: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); eamt_flush(); return respond_error(nl_hdr, 0); default: log_err("Unknown operation: %d", jool_hdr->operation); return respond_error(nl_hdr, -EINVAL); } }
static int handle_pool6791_display(struct nlmsghdr *nl_hdr, union request_pool4 *request) { struct nl_buffer *buffer; struct ipv4_prefix *prefix; int error; log_debug("Sending RFC6791 pool to userspace."); buffer = nlbuffer_create(nl_socket, nl_hdr); if (!buffer) return respond_error(nl_hdr, -ENOMEM); prefix = request->display.prefix_set ? &request->display.prefix : NULL; error = rfc6791_for_each(pool4_to_usr, buffer, prefix); error = (error >= 0) ? nlbuffer_close(buffer, error) : respond_error(nl_hdr, error); kfree(buffer); return error; }
static int handle_bib_display(struct nlmsghdr *nl_hdr, struct request_bib *request) { struct nl_buffer *buffer; struct ipv4_transport_addr *addr4; int error; log_debug("Sending BIB to userspace."); buffer = nlbuffer_create(nl_socket, nl_hdr); if (!buffer) return respond_error(nl_hdr, -ENOMEM); addr4 = request->display.addr4_set ? &request->display.addr4 : NULL; error = bibdb_iterate_by_ipv4(request->l4_proto, bib_entry_to_userspace, buffer, addr4); error = (error >= 0) ? nlbuffer_close(buffer, error) : respond_error(nl_hdr, error); kfree(buffer); return error; }
static int handle_pool4_rm(struct nlmsghdr *nl_hdr, union request_pool4 *request) { int error; if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Removing elements from the IPv4 pool."); error = pool4db_rm(request->rm.mark, request->rm.proto, &request->rm.addrs, &request->rm.ports); if (xlat_is_nat64() && !request->rm.quick) { sessiondb_delete_taddr4s(&request->rm.addrs, &request->rm.ports); bibdb_delete_taddr4s(&request->rm.addrs, &request->rm.ports); } return respond_error(nl_hdr, error); }
static int handle_eamt_display(struct nlmsghdr *nl_hdr, union request_eamt *request) { struct nl_buffer *buffer; struct ipv4_prefix *prefix4; int error; log_debug("Sending EAMT to userspace."); buffer = nlbuffer_create(nl_socket, nl_hdr); if (!buffer) return respond_error(nl_hdr, -ENOMEM); prefix4 = request->display.prefix4_set ? &request->display.prefix4 : NULL; error = eamt_for_each(eam_entry_to_userspace, buffer, prefix4); error = (error >= 0) ? nlbuffer_close(buffer, error) : respond_error(nl_hdr, error); kfree(buffer); return error; }
// // Action handler that tries to login the given user to Spotify // static void login_to_spotify_action(struct owl_state* state, char* username, char* password) { TRACE("Logging in to Spotify...\n"); state->state = OWL_STATE_LOGGING_IN; const sp_error error = sp_session_login(state->spotify_state->session, username, password, 0, NULL); if(error != SP_ERROR_OK) { ERROR("Failed to login to Spotify: %s\n", sp_error_message(error)); respond_error(state->http_request, OWL_HTTP_ERROR_LOGIN, sp_error_message(error)); } }
static int handle_pool4_display(struct nlmsghdr *nl_hdr, union request_pool4 *request) { struct nl_buffer *buffer; struct pool4_sample *offset = NULL; int error; log_debug("Sending IPv4 pool to userspace."); buffer = nlbuffer_create(nl_socket, nl_hdr); if (!buffer) return respond_error(nl_hdr, -ENOMEM); if (request->display.offset_set) offset = &request->display.offset; error = pool4db_foreach_sample(pool4_to_usr, buffer, offset); error = (error >= 0) ? nlbuffer_close(buffer, error) : respond_error(nl_hdr, error); kfree(buffer); return error; }
static int handle_eamt_test(struct nlmsghdr *nl_hdr, union request_eamt *request) { struct in6_addr addr6; struct in_addr addr4; int error; log_debug("Translating address for the user."); if (request->test.addr_is_ipv6) { error = eamt_xlat_6to4(&request->test.addr.addr6, &addr4); if (error) return respond_error(nl_hdr, error); return respond_setcfg(nl_hdr, &addr4, sizeof(addr4)); } else { error = eamt_xlat_4to6(&request->test.addr.addr4, &addr6); if (error) return respond_error(nl_hdr, error); return respond_setcfg(nl_hdr, &addr6, sizeof(addr6)); } }
static int handle_blacklist_config(struct nlmsghdr *nl_hdr, struct request_hdr *jool_hdr, union request_pool *request) { __u64 count; int error; if (xlat_is_nat64()) { log_err("Blacklist does not apply to Stateful NAT64."); return -EINVAL; } switch (jool_hdr->operation) { case OP_DISPLAY: log_debug("Sending Blacklist pool to userspace."); return handle_blacklist_display(nl_hdr, request); case OP_COUNT: log_debug("Returning address count in the Blacklist pool."); error = blacklist_count(&count); if (error) return respond_error(nl_hdr, error); return respond_setcfg(nl_hdr, &count, sizeof(count)); case OP_ADD: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Adding an address to the Blacklist pool."); return respond_error(nl_hdr, blacklist_add(&request->add.addrs)); case OP_REMOVE: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Removing an address from the Blacklist pool."); return respond_error(nl_hdr, blacklist_rm(&request->rm.addrs)); case OP_FLUSH: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Flushing the Blacklist pool..."); return respond_error(nl_hdr, blacklist_flush()); default: log_err("Unknown operation: %d", jool_hdr->operation); return respond_error(nl_hdr, -EINVAL); } }
static int handle_pool4_flush(struct nlmsghdr *nl_hdr, union request_pool4 *request) { int error; if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Flushing the IPv4 pool..."); error = pool4db_flush(); /* * Well, pool4db_flush only errors on memory allocation failures, * so I guess clearing BIB and session even if pool4db_flush fails * is a good idea. */ if (xlat_is_nat64() && !request->flush.quick) { sessiondb_flush(); bibdb_flush(); } return respond_error(nl_hdr, error); }
static int handle_session_display(struct nlmsghdr *nl_hdr, struct request_session *request) { struct nl_buffer *buffer; struct ipv4_transport_addr *remote4 = NULL; struct ipv4_transport_addr *local4 = NULL; int error; log_debug("Sending session table to userspace."); buffer = nlbuffer_create(nl_socket, nl_hdr); if (!buffer) return respond_error(nl_hdr, -ENOMEM); if (request->display.connection_set) { remote4 = &request->display.remote4; local4 = &request->display.local4; } error = sessiondb_iterate_by_ipv4(request->l4_proto, session_entry_to_userspace, buffer, remote4, local4); error = (error >= 0) ? nlbuffer_close(buffer, error) : respond_error(nl_hdr, error); kfree(buffer); return error; }
// // -- Spotify callbacks --------------------------------------------------------------------------- // static void logged_in_callback(sp_session *session, sp_error error) { TRACE("logged_in_callback\n"); struct owl_state* state = sp_session_userdata(session); if(error == SP_ERROR_OK) { state->state = OWL_STATE_IDLE; INFO("Logged in to Spotify!\n"); respond_success(state->http_request); } else { state->state = OWL_STATE_INITIALIZED; ERROR("Failed to login to Spotify: %s\n", sp_error_message(error)); respond_error(state->http_request, OWL_HTTP_ERROR_LOGIN, sp_error_message(error)); } }
static int handle_bib_config(struct nlmsghdr *nl_hdr, struct request_hdr *nat64_hdr, struct request_bib *request) { __u64 count; int error; if (nat64_is_stateless()) { log_err("SIIT doesn't have BIBs."); return -EINVAL; } switch (nat64_hdr->operation) { case OP_DISPLAY: return handle_bib_display(nl_hdr, request); case OP_COUNT: log_debug("Returning BIB count."); error = bibdb_count(request->l4_proto, &count); if (error) return respond_error(nl_hdr, error); return respond_setcfg(nl_hdr, &count, sizeof(count)); case OP_ADD: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Adding BIB entry."); return respond_error(nl_hdr, add_static_route(request)); case OP_REMOVE: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Removing BIB entry."); return respond_error(nl_hdr, delete_static_route(request)); default: log_err("Unknown operation: %d", nat64_hdr->operation); return respond_error(nl_hdr, -EINVAL); } }
int respond_success(FILE * fp, long long length) { char str[32]; sprintf(str, "%llu", length); return respond_error(fp, 0, str); }
// // Function called when a new HTTP request have been recieved. // static void http_handler(struct evhttp_request *request, void *userdata) { struct owl_state* state = userdata; // Setup general response headers struct evkeyvalq *headers = evhttp_request_get_output_headers(request); evhttp_add_header(headers, "Server", USER_AGENT); // Get the requested URI const char* uri = evhttp_request_get_uri(request); const int http_method = evhttp_request_get_command(request); if( http_method != EVHTTP_REQ_GET && http_method != EVHTTP_REQ_PUT && http_method != EVHTTP_REQ_POST) { evhttp_send_error(request, 501, "Not Implemented"); return; } TRACE("Received HTTP request: %s (method %d)\n", uri, http_method); // Keep the request for async usage state->http_request = request; // // Retrieve application state (sync) if(string_starts_with(uri, "/api/state") && http_method == EVHTTP_REQ_GET) { state_action(state); } // // Shutdown owl application (async) else if(string_starts_with(uri, "/api/shutdown") && http_method == EVHTTP_REQ_GET) { shutdown_action(state); } // // Try to login to Spotify (async) else if(string_starts_with(uri, "/api/login") && http_method == EVHTTP_REQ_GET) { char* username = extract_uri_section(2, uri); char* password = extract_uri_section(3, uri); if(username != NULL && password != NULL) { login_to_spotify_action(state, username, password); } else { WARN("Could not extract username and password in order to login to Spotify!\n"); respond_error(request, OWL_HTTO_ERROR_NO_LOGIN_DETAILS, "No username or password given"); } } else if(string_starts_with(uri, "/api/login") && http_method == EVHTTP_REQ_POST) { TRACE("POST LOGIN\n"); get_post_argument(request, "username"); evhttp_send_error(request, 501, "Not Implemented"); } // // Logout from spotify (async) else if(string_starts_with(uri, "/api/logout") && http_method == EVHTTP_REQ_GET) { if(state->state > OWL_STATE_LOGGING_IN && state->state < OWL_STATE_LOGGING_OUT) logout_from_spotify_action(state); else respond_success(request); } // // Clear the entire queue else if(string_starts_with(uri, "/api/queue/clear") && http_method == EVHTTP_REQ_GET) { if(state->state < OWL_STATE_IDLE || state->state > OWL_STATE_PLAYING) { respond_error(request, OWL_HTTP_ERROR_NOT_LOGGED_IN, "Operation not allowed when not logged in"); } else { const int size = queue_size(state->spotify_state->queue); for(int i = 0; i < size; i++) { owl_track *track = pop_from_queue(state->spotify_state->queue); free_track(track); } respond_success(request); } } // // Get the current playback queue (sync) else if(string_starts_with(uri, "/api/queue") && http_method == EVHTTP_REQ_GET) { if(state->state < OWL_STATE_IDLE || state->state > OWL_STATE_PLAYING) { WARN("Operation not allowed at this state (%d)\n", state->state); respond_error(request, OWL_HTTP_ERROR_NOT_LOGGED_IN, "Operation not allowed when not logged in"); } else { respond_with_queue(state->http_request, state->spotify_state->queue); } } // // Serve static file immediately else { // Create the buffer to retrn as content struct evbuffer *content_buffer = evbuffer_new(); // If not a handler this is a static request char *static_file = (char *) malloc(strlen(doc_root) + strlen(uri) + 1); stpcpy(stpcpy(static_file, doc_root), uri); TRACE("Looking for static file: %s\n", static_file); bool file_exists = 1; struct stat st; if(stat(static_file, &st) == -1 || S_ISDIR(st.st_mode)) { file_exists = 0; evhttp_send_error(request, HTTP_NOTFOUND, "Not Found"); } if(file_exists) { const int file_size = st.st_size; FILE *fp = fopen(static_file, "r"); const char* content_type = resolve_content_type(static_file); evbuffer_add_file(content_buffer, fileno(fp), 0, file_size); // will close TRACE("Resolving content type for filename: %s to: %s\n", static_file, content_type); evhttp_add_header(headers, "Content-Type", content_type); evhttp_send_reply(request, HTTP_OK, "OK", content_buffer); } free(static_file); // Send the data evhttp_send_reply(request, HTTP_OK, USER_AGENT, content_buffer); // Free memrory evbuffer_free(content_buffer); } return; }
void handle_client(int fd, const char * userTest, const char * passTest) { FILE * fp = fdopen(fd, "w+"); char * user, * pass, * path; long long initial; if (read_client_request(fp, &user, &pass, &path, &initial) < 0) { return; } if (strcmp(user, userTest) != 0 || strcmp(pass, passTest) != 0) { respond_error(fp, PROTOCOL_ERROR_AUTH, "Login incorrect."); goto handleError; } #ifdef __linux__ struct stat64 info; if (stat64(path, &info) < 0) { #else struct stat info if (stat(path, &info) < 0) { #endif respond_error(fp, PROTOCOL_ERROR_NO_FILE, "Could not stat file."); goto handleError; } if (S_ISDIR(info.st_mode)) { respond_error(fp, PROTOCOL_ERROR_NOT_FILE, "Could not send directory."); goto handleError; } if (initial > info.st_size) { respond_error(fp, PROTOCOL_ERROR_INVALID_INITIAL, "Invalid initial offset."); goto handleError; } #ifdef __linux__ FILE * readFile = fopen64(path, "r"); #else FILE * readfile = fopen(path, "r"); #endif if (!readFile) { perror("fopen"); respond_error(fp, PROTOCOL_ERROR_INTERNAL, "fopen() failed"); goto handleError; } if (respond_success(fp, info.st_size - initial) < 0) { fclose(readFile); goto handleError; } // read file from start offset fseek(readFile, initial, SEEK_SET); char buff[512]; while (!feof(readFile)) { int got = fread(buff, 1, 512, readFile); if (got == 0) break; if (fwrite(buff, 1, got, fp) != got) { break; } } fclose(readFile); handleError: fclose(fp); free(user); free(pass); free(path); return; } void sigchild_handler(int signal) { int status; wait(&status); }