From 6c2e8cd7b2110fc2f45af5a4bcfa8b640d75f288 Mon Sep 17 00:00:00 2001 From: Kalle Olavi Niemitalo Date: Sun, 3 Aug 2008 15:24:26 +0300 Subject: [PATCH] Bug 1013: Don't assume errno is between 0 and 100000 Replace almost all uses of enum connection_state with struct connection_status. This removes the assumption that errno values used by the system are between 0 and 100000. The GNU Hurd uses values like ENOENT = 0x40000002 and EMIG_SERVER_DIED = -308. This commit is derived from my attachments 450 and 467 to bug 1013. --- NEWS | 1 + src/dialogs/download.c | 4 +- src/dialogs/menu.c | 9 +- src/dialogs/status.c | 8 +- src/document/css/css.c | 2 +- src/encoding/encoding.c | 26 ++--- src/encoding/encoding.h | 4 +- src/network/connection.c | 75 ++++++++------- src/network/connection.h | 10 +- src/network/socket.c | 101 +++++++++++--------- src/network/socket.h | 14 +-- src/network/ssl/socket.c | 20 ++-- src/network/state.c | 6 +- src/network/state.h | 63 +++++++++--- src/protocol/about.c | 2 +- src/protocol/bittorrent/bittorrent.c | 2 +- src/protocol/bittorrent/bittorrent.h | 2 +- src/protocol/bittorrent/common.c | 17 ++-- src/protocol/bittorrent/common.h | 4 +- src/protocol/bittorrent/connection.c | 27 +++--- src/protocol/bittorrent/dialogs.c | 14 +-- src/protocol/bittorrent/peerconnect.c | 70 +++++++------- src/protocol/bittorrent/peerconnect.h | 2 +- src/protocol/bittorrent/peerwire.c | 20 ++-- src/protocol/bittorrent/tracker.c | 26 ++--- src/protocol/common.c | 6 +- src/protocol/common.h | 2 +- src/protocol/data.c | 10 +- src/protocol/file/cgi.c | 15 +-- src/protocol/file/file.c | 33 +++---- src/protocol/finger/finger.c | 10 +- src/protocol/fsp/fsp.c | 86 ++++++++++------- src/protocol/ftp/ftp.c | 132 ++++++++++++++------------ src/protocol/gopher/gopher.c | 20 ++-- src/protocol/http/http.c | 56 ++++++----- src/protocol/nntp/connection.c | 69 +++++++------- src/protocol/nntp/response.c | 30 +++--- src/protocol/nntp/response.h | 2 +- src/protocol/protocol.c | 8 +- src/protocol/proxy.c | 18 ++-- src/protocol/proxy.h | 4 +- src/protocol/smb/smb2.c | 76 +++++++++------ src/protocol/test/stub.c | 2 +- src/session/download.c | 10 +- src/session/download.h | 4 +- src/session/session.c | 9 +- src/session/session.h | 2 +- src/session/task.c | 5 +- src/viewer/dump/dump.c | 2 +- 49 files changed, 628 insertions(+), 512 deletions(-) diff --git a/NEWS b/NEWS index a02c10882..954a1f62b 100644 --- a/NEWS +++ b/NEWS @@ -21,6 +21,7 @@ includes the changes listed under "ELinks 0.11.4.GIT now" below. JS_CallFunction, which can crash if given a closure. * critical bug 1031: Use the same JSRuntime for both user SMJS and scripts on web pages, to work around SpiderMonkey bug 378918. +* bug 1013: Don't assume errno values are between 0 and 100000 * bug 1022: Add connection.ssl.trusted_ca_file setting for GnuTLS. Before this, ELinks did not trust any certificate authorities when it used GnuTLS, so certificate verification always failed if you diff --git a/src/dialogs/download.c b/src/dialogs/download.c index 825e0b53d..011657879 100644 --- a/src/dialogs/download.c +++ b/src/dialogs/download.c @@ -132,7 +132,7 @@ download_dialog_layouter(struct dialog_data *dlg_data) && download->progress->size >= 0); #if CONFIG_BITTORRENT int bittorrent = (file_download->uri->protocol == PROTOCOL_BITTORRENT - && (show_meter || download->state == S_RESUME)); + && (show_meter || is_in_state(download->state, S_RESUME))); #endif redraw_below_window(dlg_data->win); @@ -402,7 +402,7 @@ draw_file_download(struct listbox_item *item, struct listbox_context *context, if (!download->progress || download->progress->size < 0 - || download->state != S_TRANS + || !is_in_state(download->state, S_TRANS) || !has_progress(download->progress)) { /* TODO: Show trimmed error message. */ return; diff --git a/src/dialogs/menu.c b/src/dialogs/menu.c index b39015c3c..b8233aeb9 100644 --- a/src/dialogs/menu.c +++ b/src/dialogs/menu.c @@ -74,7 +74,8 @@ save_url(struct session *ses, unsigned char *url) uri = get_translated_uri(url, ses->tab->term->cwd); if (!uri) { - print_error_dialog(ses, S_BAD_URL, uri, PRI_CANCEL); + print_error_dialog(ses, connection_state(S_BAD_URL), + uri, PRI_CANCEL); return; } @@ -568,12 +569,14 @@ query_file(struct session *ses, struct uri *uri, void *data, * the checking? --jonas */ if (uri->protocol == PROTOCOL_UNKNOWN) { - print_error_dialog(ses, S_UNKNOWN_PROTOCOL, uri, PRI_CANCEL); + print_error_dialog(ses, connection_state(S_UNKNOWN_PROTOCOL), + uri, PRI_CANCEL); return; } if (get_protocol_external_handler(ses->tab->term, uri)) { - print_error_dialog(ses, S_EXTERNAL_PROTOCOL, uri, PRI_CANCEL); + print_error_dialog(ses, connection_state(S_EXTERNAL_PROTOCOL), + uri, PRI_CANCEL); return; } diff --git a/src/dialogs/status.c b/src/dialogs/status.c index cfe14609d..908ad0b2a 100644 --- a/src/dialogs/status.c +++ b/src/dialogs/status.c @@ -214,12 +214,12 @@ display_status_bar(struct session *ses, struct terminal *term, int tabs_count) static int last_current_link; int ncl = doc_view->vs->current_link; - if (download->state == S_INTERRUPTED + if (is_in_state(download->state, S_INTERRUPTED) && ncl != last_current_link) - download->state = S_OK; + download->state = connection_state(S_OK); last_current_link = ncl; - if (download->state == S_OK) { + if (is_in_state(download->state, S_OK)) { if (get_current_link(doc_view)) { msg = get_current_link_info_and_title(ses, doc_view); } else if (ses->navigate_mode == NAVIGATE_CURSOR_ROUTING) { @@ -340,7 +340,7 @@ display_tab_bar(struct session *ses, struct terminal *term, int tabs_count) } else { download = get_current_download(tab_ses); - if (download && download->state != S_OK) { + if (download && !is_in_state(download->state, S_OK)) { color = loading_color; } else if (!tab_ses || !tab_ses->status.visited) { color = fresh_color; diff --git a/src/document/css/css.c b/src/document/css/css.c index c1a4a7d75..c7d21def4 100644 --- a/src/document/css/css.c +++ b/src/document/css/css.c @@ -94,7 +94,7 @@ import_css_file(struct css_stylesheet *css, struct uri *base_uri, add_bytes_to_string(&filename, url, urllen); - if (read_encoded_file(&filename, &string) == S_OK) { + if (is_in_state(read_encoded_file(&filename, &string), S_OK)) { unsigned char *end = string.source + string.length; css->import_level++; diff --git a/src/encoding/encoding.c b/src/encoding/encoding.c index 672c15119..d019dab31 100644 --- a/src/encoding/encoding.c +++ b/src/encoding/encoding.c @@ -223,10 +223,10 @@ try_encoding_extensions(struct string *filename, int *fd) * whether the true end of the stream has been reached. * * @return a connection state. S_OK if all is well. */ -enum connection_state +struct connection_state read_file(struct stream_encoded *stream, int readsize, struct string *page) { - if (!init_string(page)) return S_OUT_OF_MEM; + if (!init_string(page)) return connection_state(S_OUT_OF_MEM); /* We read with granularity of stt.st_size (given as @readsize) - this * does best job for uncompressed files, and doesn't hurt for @@ -248,17 +248,17 @@ read_file(struct stream_encoded *stream, int readsize, struct string *page) * do. Since errno == 0 == S_WAIT and we cannot have * that. */ if (errno) - return (enum connection_state) -errno; + return connection_state_for_errno(errno); /* FIXME: This is indeed an internal error. If readed from a * corrupted encoded file nothing or only some of the * data will be read. */ - return S_ENCODE_ERROR; + return connection_state(S_ENCODE_ERROR); } else if (readlen == 0) { /* NUL-terminate just in case */ page->source[page->length] = '\0'; - return S_OK; + return connection_state(S_OK); } page->length += readlen; @@ -276,7 +276,7 @@ read_file(struct stream_encoded *stream, int readsize, struct string *page) } done_string(page); - return S_OUT_OF_MEM; + return connection_state(S_OUT_OF_MEM); } static inline int @@ -291,14 +291,14 @@ is_stdin_pipe(struct stat *stt, struct string *filename) S_ISFIFO(stt->st_mode)); } -enum connection_state +struct connection_state read_encoded_file(struct string *filename, struct string *page) { struct stream_encoded *stream; struct stat stt; enum stream_encoding encoding = ENCODING_NONE; int fd = open(filename->source, O_RDONLY | O_NOCTTY); - enum connection_state state = -errno; + struct connection_state state = connection_state_for_errno(errno); if (fd == -1 && get_opt_bool("protocol.file.try_encoding_extensions")) { encoding = try_encoding_extensions(filename, &fd); @@ -323,7 +323,7 @@ read_encoded_file(struct string *filename, struct string *page) /* Do all the necessary checks before trying to read the file. * @state code is used to block further progress. */ if (fstat(fd, &stt)) { - state = -errno; + state = connection_state_for_errno(errno); } else if (!S_ISREG(stt.st_mode) && encoding != ENCODING_NONE) { /* We only want to open regular encoded files. */ @@ -331,10 +331,10 @@ read_encoded_file(struct string *filename, struct string *page) } else if (!S_ISREG(stt.st_mode) && !is_stdin_pipe(&stt, filename) && !get_opt_bool("protocol.file.allow_special_files")) { - state = S_FILE_TYPE; + state = connection_state(S_FILE_TYPE); } else if (!(stream = open_encoded(fd, encoding))) { - state = S_OUT_OF_MEM; + state = connection_state(S_OUT_OF_MEM); } else { int readsize = (int) stt.st_size; @@ -343,9 +343,9 @@ read_encoded_file(struct string *filename, struct string *page) /* FIXME: See bug 497 for info about support for big files. */ if (readsize != stt.st_size || readsize < 0) { #ifdef EFBIG - state = (enum connection_state) -(EFBIG); + state = connection_state_for_errno(EFBIG); #else - state = S_FILE_ERROR; + state = connection_state(S_FILE_ERROR); #endif } else { diff --git a/src/encoding/encoding.h b/src/encoding/encoding.h index 00b4ab2cf..68b656c85 100644 --- a/src/encoding/encoding.h +++ b/src/encoding/encoding.h @@ -39,10 +39,10 @@ enum stream_encoding guess_encoding(unsigned char *filename); const unsigned char *get_encoding_name(enum stream_encoding encoding); /* Read from open @stream into the @page string */ -enum connection_state +struct connection_state read_file(struct stream_encoded *stream, int readsize, struct string *page); /* Reads the file with the given @filename into the string @source. */ -enum connection_state read_encoded_file(struct string *filename, struct string *source); +struct connection_state read_encoded_file(struct string *filename, struct string *source); #endif diff --git a/src/network/connection.c b/src/network/connection.c index 3c1da9ada..2f4271bd0 100644 --- a/src/network/connection.c +++ b/src/network/connection.c @@ -228,28 +228,28 @@ check_queue_bugs(void) #endif static void -set_connection_socket_state(struct socket *socket, enum connection_state state) +set_connection_socket_state(struct socket *socket, struct connection_state state) { assert(socket); set_connection_state(socket->conn, state); } static void -set_connection_socket_timeout(struct socket *socket, enum connection_state state) +set_connection_socket_timeout(struct socket *socket, struct connection_state state) { assert(socket); set_connection_timeout(socket->conn); } static void -retry_connection_socket(struct socket *socket, enum connection_state state) +retry_connection_socket(struct socket *socket, struct connection_state state) { assert(socket); retry_connection(socket->conn, state); } static void -done_connection_socket(struct socket *socket, enum connection_state state) +done_connection_socket(struct socket *socket, struct connection_state state) { assert(socket); abort_connection(socket->conn, state); @@ -338,7 +338,7 @@ stat_timer(struct connection *conn) } void -set_connection_state(struct connection *conn, enum connection_state state) +set_connection_state(struct connection *conn, struct connection_state state) { struct download *download; struct progress *progress = conn->progress; @@ -347,7 +347,7 @@ set_connection_state(struct connection *conn, enum connection_state state) conn->prev_error = conn->state; conn->state = state; - if (conn->state == S_TRANS) { + if (is_in_state(conn->state, S_TRANS)) { if (progress->timer == TIMER_ID_UNDEF) { start_update_progress(progress, (void (*)(void *)) stat_timer, conn); update_connection_progress(conn); @@ -412,14 +412,14 @@ free_connection_data(struct connection *conn) kill_timer(&conn->timer); - if (conn->state != S_WAIT) + if (!is_in_state(conn->state, S_WAIT)) done_host_connection(conn); } void notify_connection_callbacks(struct connection *conn) { - enum connection_state state = conn->state; + struct connection_state state = conn->state; struct download *download, *next; foreachsafe (download, next, conn->downloads) { @@ -439,7 +439,7 @@ done_connection(struct connection *conn) * connection is in a result state. If it is not already it is an * internal bug. This should never happen but it does. ;) --jonas */ if (!is_in_result_state(conn->state)) - set_connection_state(conn, S_INTERNAL); + set_connection_state(conn, connection_state(S_INTERNAL)); del_from_list(conn); notify_connection_callbacks(conn); @@ -696,7 +696,7 @@ static inline void suspend_connection(struct connection *conn) { interrupt_connection(conn); - set_connection_state(conn, S_WAIT); + set_connection_state(conn, connection_state(S_WAIT)); } static void @@ -710,7 +710,7 @@ run_connection(struct connection *conn) if_assert_failed return; if (!add_host_connection(conn)) { - set_connection_state(conn, S_OUT_OF_MEM); + set_connection_state(conn, connection_state(S_OUT_OF_MEM)); done_connection(conn); return; } @@ -723,12 +723,12 @@ run_connection(struct connection *conn) /* Set certain state on a connection and then abort the connection. */ void -abort_connection(struct connection *conn, enum connection_state state) +abort_connection(struct connection *conn, struct connection_state state) { assertm(is_in_result_state(state), "connection didn't end in result state (%d)", state); - if (state == S_OK && conn->cached) + if (is_in_state(state, S_OK) && conn->cached) normalize_cache_entry(conn->cached, conn->from); set_connection_state(conn, state); @@ -740,7 +740,7 @@ abort_connection(struct connection *conn, enum connection_state state) /* Set certain state on a connection and then retry the connection. */ void -retry_connection(struct connection *conn, enum connection_state state) +retry_connection(struct connection *conn, struct connection_state state) { int max_tries = get_opt_int("connection.retries"); @@ -767,7 +767,7 @@ try_to_suspend_connection(struct connection *conn, struct uri *uri) foreachback (c, connection_queue) { if (get_priority(c) <= priority) return -1; - if (c->state == S_WAIT) continue; + if (is_in_state(c->state, S_WAIT)) continue; if (c->uri->post && get_priority(c) < PRI_CANCEL) continue; if (uri && !compare_uri(uri, c->uri, URI_HOST)) continue; suspend_connection(c); @@ -812,7 +812,8 @@ again: struct connection *cc = c; c = c->next; - if (cc->state == S_WAIT && get_keepalive_connection(cc) + if (is_in_state(cc->state, S_WAIT) + && get_keepalive_connection(cc) && try_connection(cc, max_conns_to_host, max_conns)) goto again; } @@ -821,7 +822,7 @@ again: struct connection *cc = c; c = c->next; - if (cc->state == S_WAIT + if (is_in_state(cc->state, S_WAIT) && try_connection(cc, max_conns_to_host, max_conns)) goto again; } @@ -831,8 +832,8 @@ again: again2: foreachback (conn, connection_queue) { if (get_priority(conn) < PRI_CANCEL) break; - if (conn->state == S_WAIT) { - set_connection_state(conn, S_INTERRUPTED); + if (is_in_state(conn->state, S_WAIT)) { + set_connection_state(conn, connection_state(S_INTERRUPTED)); done_connection(conn); goto again2; } @@ -854,14 +855,14 @@ load_uri(struct uri *uri, struct uri *referrer, struct download *download, struct cache_entry *cached; struct connection *conn; struct uri *proxy_uri, *proxied_uri; - enum connection_state connection_state = S_OK; + struct connection_state error_state = connection_state(S_OK); if (download) { download->conn = NULL; download->cached = NULL; download->pri = pri; - download->state = S_OUT_OF_MEM; - download->prev_error = 0; + download->state = connection_state(S_OUT_OF_MEM); + download->prev_error = connection_state(0); } #ifdef CONFIG_DEBUG @@ -871,7 +872,7 @@ load_uri(struct uri *uri, struct uri *referrer, struct download *download, foreach (assigned, conn->downloads) { assertm(assigned != download, "Download assigned to '%s'", struri(conn->uri)); if_assert_failed { - download->state = S_INTERNAL; + download->state = connection_state(S_INTERNAL); if (download->callback) download->callback(download, download->data); return 0; @@ -885,7 +886,7 @@ load_uri(struct uri *uri, struct uri *referrer, struct download *download, if (cached) { if (download) { download->cached = cached; - download->state = S_OK; + download->state = connection_state(S_OK); /* XXX: * This doesn't work since sometimes |download->progress| * is undefined and contains random memory locations. @@ -902,7 +903,7 @@ load_uri(struct uri *uri, struct uri *referrer, struct download *download, } proxied_uri = get_proxied_uri(uri); - proxy_uri = get_proxy_uri(uri, &connection_state); + proxy_uri = get_proxy_uri(uri, &error_state); if (!proxy_uri || !proxied_uri @@ -910,12 +911,13 @@ load_uri(struct uri *uri, struct uri *referrer, struct download *download, && !proxy_uri->hostlen)) { if (download) { - if (connection_state == S_OK) { - connection_state = proxy_uri && proxied_uri - ? S_BAD_URL : S_OUT_OF_MEM; + if (is_in_state(error_state, S_OK)) { + error_state = proxy_uri && proxied_uri + ? connection_state(S_BAD_URL) + : connection_state(S_OUT_OF_MEM); } - download->state = connection_state; + download->state = error_state; download->callback(download, download->data); } if (proxy_uri) done_uri(proxy_uri); @@ -955,7 +957,7 @@ load_uri(struct uri *uri, struct uri *referrer, struct download *download, conn = init_connection(proxy_uri, proxied_uri, referrer, start, cache_mode, pri); if (!conn) { if (download) { - download->state = S_OUT_OF_MEM; + download->state = connection_state(S_OUT_OF_MEM); download->callback(download, download->data); } if (proxy_uri) done_uri(proxy_uri); @@ -971,12 +973,12 @@ load_uri(struct uri *uri, struct uri *referrer, struct download *download, download->progress = conn->progress; download->conn = conn; download->cached = NULL; - download->state = S_OK; + download->state = connection_state(S_OK); add_to_list(conn->downloads, download); } add_to_queue(conn); - set_connection_state(conn, S_WAIT); + set_connection_state(conn, connection_state(S_WAIT)); check_queue_bugs(); @@ -1002,7 +1004,7 @@ cancel_download(struct download *download, int interrupt) check_queue_bugs(); - download->state = S_INTERRUPTED; + download->state = connection_state(S_INTERRUPTED); del_from_list(download); conn = download->conn; @@ -1016,7 +1018,7 @@ cancel_download(struct download *download, int interrupt) conn->pri[PRI_CANCEL]++; if (conn->detached || interrupt) - abort_connection(conn, S_INTERRUPTED); + abort_connection(conn, connection_state(S_INTERRUPTED)); } sort_queue(); @@ -1164,7 +1166,8 @@ void abort_all_connections(void) { while (!list_empty(connection_queue)) { - abort_connection(connection_queue.next, S_INTERRUPTED); + abort_connection(connection_queue.next, + connection_state(S_INTERRUPTED)); } abort_all_keepalive_connections(); @@ -1177,7 +1180,7 @@ abort_background_connections(void) foreachsafe (conn, next, connection_queue) { if (get_priority(conn) >= PRI_CANCEL) - abort_connection(conn, S_INTERRUPTED); + abort_connection(conn, connection_state(S_INTERRUPTED)); } } diff --git a/src/network/connection.h b/src/network/connection.h index f5b56c602..97a57cdca 100644 --- a/src/network/connection.h +++ b/src/network/connection.h @@ -40,8 +40,8 @@ struct connection { unsigned int id; - enum connection_state state; - enum connection_state prev_error; + struct connection_state state; + struct connection_state prev_error; /* The communication socket with the other side. */ struct socket *socket; @@ -81,14 +81,14 @@ int get_keepalive_connections_count(void); int get_connections_connecting_count(void); int get_connections_transfering_count(void); -void set_connection_state(struct connection *, enum connection_state); +void set_connection_state(struct connection *, struct connection_state); int has_keepalive_connection(struct connection *); void add_keepalive_connection(struct connection *conn, long timeout_in_seconds, void (*done)(struct connection *)); -void abort_connection(struct connection *, enum connection_state); -void retry_connection(struct connection *, enum connection_state); +void abort_connection(struct connection *, struct connection_state); +void retry_connection(struct connection *, struct connection_state); void cancel_download(struct download *download, int interrupt); void move_download(struct download *old, struct download *new, diff --git a/src/network/socket.c b/src/network/socket.c index aac3bf14b..4179b1526 100644 --- a/src/network/socket.c +++ b/src/network/socket.c @@ -167,13 +167,13 @@ close_socket(struct socket *socket) void dns_exception(struct socket *socket) { - connect_socket(socket, S_EXCEPT); + connect_socket(socket, connection_state(S_EXCEPT)); } static void exception(struct socket *socket) { - socket->ops->retry(socket, S_EXCEPT); + socket->ops->retry(socket, connection_state(S_EXCEPT)); } @@ -181,23 +181,23 @@ void timeout_socket(struct socket *socket) { if (!socket->connect_info) { - socket->ops->retry(socket, S_TIMEOUT); + socket->ops->retry(socket, connection_state(S_TIMEOUT)); return; } /* Is the DNS resolving still in progress? */ if (socket->connect_info->dnsquery) { - socket->ops->done(socket, S_TIMEOUT); + socket->ops->done(socket, connection_state(S_TIMEOUT)); return; } /* Try the next address, */ - connect_socket(socket, S_TIMEOUT); + connect_socket(socket, connection_state(S_TIMEOUT)); /* Reset the timeout if connect_socket() started a new attempt * to connect. */ if (socket->connect_info) - socket->ops->set_timeout(socket, 0); + socket->ops->set_timeout(socket, connection_state(0)); } @@ -209,7 +209,7 @@ dns_found(struct socket *socket, struct sockaddr_storage *addr, int addrlen) int size; if (!addr) { - socket->ops->done(socket, S_NO_DNS); + socket->ops->done(socket, connection_state(S_NO_DNS)); return; } @@ -219,7 +219,7 @@ dns_found(struct socket *socket, struct sockaddr_storage *addr, int addrlen) connect_info->addr = mem_alloc(size); if (!connect_info->addr) { - socket->ops->done(socket, S_OUT_OF_MEM); + socket->ops->done(socket, connection_state(S_OUT_OF_MEM)); return; } @@ -233,7 +233,7 @@ dns_found(struct socket *socket, struct sockaddr_storage *addr, int addrlen) * problem if connect_socket() fails without doing any system calls * which is only the case when forcing the IP family. So it is better to * handle it in connect_socket(). */ - connect_socket(socket, S_CONN); + connect_socket(socket, connection_state(S_CONN)); } void @@ -244,17 +244,17 @@ make_connection(struct socket *socket, struct uri *uri, struct connect_info *connect_info; enum dns_result result; - socket->ops->set_timeout(socket, 0); + socket->ops->set_timeout(socket, connection_state(0)); if (!host) { - socket->ops->retry(socket, S_OUT_OF_MEM); + socket->ops->retry(socket, connection_state(S_OUT_OF_MEM)); return; } connect_info = init_connection_info(uri, socket, connect_done); if (!connect_info) { mem_free(host); - socket->ops->retry(socket, S_OUT_OF_MEM); + socket->ops->retry(socket, connection_state(S_OUT_OF_MEM)); return; } @@ -278,7 +278,7 @@ make_connection(struct socket *socket, struct uri *uri, mem_free(host); if (result == DNS_ASYNC) - socket->ops->set_state(socket, S_DNS); + socket->ops->set_state(socket, connection_state(S_DNS)); } @@ -316,7 +316,8 @@ get_pasv_socket(struct socket *ctrl_socket, struct sockaddr_storage *addr) if (getsockname(ctrl_socket->fd, pasv_addr, &len)) { sock_error: if (sock != -1) close(sock); - ctrl_socket->ops->retry(ctrl_socket, -errno); + ctrl_socket->ops->retry(ctrl_socket, + connection_state_for_errno(errno)); return -1; } @@ -454,7 +455,7 @@ complete_connect_socket(struct socket *socket, struct uri *uri, assert(uri && socket); connect_info = init_connection_info(uri, socket, done); if (!connect_info) { - socket->ops->done(socket, S_OUT_OF_MEM); + socket->ops->done(socket, connection_state(S_OUT_OF_MEM)); return; } @@ -482,6 +483,7 @@ static void connected(struct socket *socket) { int err = 0; + struct connection_state state = connection_state(0); socklen_t len = sizeof(err); assertm(socket->connect_info != NULL, "Lost connect_info!"); @@ -490,17 +492,21 @@ connected(struct socket *socket) if (getsockopt(socket->fd, SOL_SOCKET, SO_ERROR, (void *) &err, &len) == 0) { /* Why does EMX return so large values? */ if (err >= 10000) err -= 10000; + if (err != 0) + state = connection_state_for_errno(err); + else + state = connection_state(0); } else { /* getsockopt() failed */ - if (errno > 0) - err = errno; + if (errno != 0) + state = connection_state_for_errno(errno); else - err = -(S_STATE); + state = connection_state(S_STATE); } - if (err > 0) { + if (!is_in_state(state, 0)) { /* There are maybe still some more candidates. */ - connect_socket(socket, -err); + connect_socket(socket, state); return; } @@ -508,7 +514,7 @@ connected(struct socket *socket) } void -connect_socket(struct socket *csocket, enum connection_state state) +connect_socket(struct socket *csocket, struct connection_state state) { int sock = -1; struct connect_info *connect_info = csocket->connect_info; @@ -640,7 +646,7 @@ connect_socket(struct socket *csocket, enum connection_state state) /* It will take some more time... */ set_handlers(sock, NULL, (select_handler_T) connected, (select_handler_T) dns_exception, csocket); - csocket->ops->set_state(csocket, S_CONN); + csocket->ops->set_state(csocket, connection_state(S_CONN)); return; } @@ -658,7 +664,7 @@ connect_socket(struct socket *csocket, enum connection_state state) * what matters is the last one because we do not know the * previous one's errno, and the added complexity wouldn't * really be worth it. */ - csocket->ops->done(csocket, S_LOCAL_ONLY); + csocket->ops->done(csocket, connection_state(S_LOCAL_ONLY)); return; } @@ -666,10 +672,10 @@ connect_socket(struct socket *csocket, enum connection_state state) * new. Else use the S_DNS _progress_ state to make sure that no * download callbacks will report any errors. */ if (trno != connect_info->triedno && !silent_fail) - state = -errno; + state = connection_state_for_errno(errno); else if (trno == -1 && silent_fail) /* All failed. */ - state = S_NO_FORCED_DNS; + state = connection_state(S_NO_FORCED_DNS); csocket->ops->retry(csocket, state); } @@ -704,14 +710,14 @@ write_select(struct socket *socket) assertm(wb != NULL, "write socket has no buffer"); if_assert_failed { - socket->ops->done(socket, S_INTERNAL); + socket->ops->done(socket, connection_state(S_INTERNAL)); return; } /* We are making some progress, therefore reset the timeout; ie. when * uploading large files the time needed for all the data to be sent can * easily exceed the timeout. */ - socket->ops->set_timeout(socket, 0); + socket->ops->set_timeout(socket, connection_state(0)); #if 0 printf("ws: %d\n",wb->length-wb->pos); @@ -731,17 +737,17 @@ write_select(struct socket *socket) switch (wr) { case SOCKET_CANT_WRITE: - socket->ops->retry(socket, S_CANT_WRITE); + socket->ops->retry(socket, connection_state(S_CANT_WRITE)); break; case SOCKET_SYSCALL_ERROR: - socket->ops->retry(socket, -errno); + socket->ops->retry(socket, connection_state_for_errno(errno)); break; case SOCKET_INTERNAL_ERROR: /* The global errno variable is used for passing * internal connection_state error value. */ - socket->ops->done(socket, -errno); + socket->ops->done(socket, connection_state(errno)); break; default: @@ -777,7 +783,7 @@ write_select(struct socket *socket) void write_to_socket(struct socket *socket, unsigned char *data, int len, - enum connection_state state, socket_write_T write_done) + struct connection_state state, socket_write_T write_done) { select_handler_T read_handler; struct write_buffer *wb; @@ -787,11 +793,11 @@ write_to_socket(struct socket *socket, unsigned char *data, int len, assert(len > 0); if_assert_failed return; - socket->ops->set_timeout(socket, 0); + socket->ops->set_timeout(socket, connection_state(0)); wb = mem_alloc(sizeof(*wb) + len); if (!wb) { - socket->ops->done(socket, S_OUT_OF_MEM); + socket->ops->done(socket, connection_state(S_OUT_OF_MEM)); return; } @@ -834,14 +840,14 @@ read_select(struct socket *socket) assertm(rb != NULL, "read socket has no buffer"); if_assert_failed { - socket->ops->done(socket, S_INTERNAL); + socket->ops->done(socket, connection_state(S_INTERNAL)); return; } /* We are making some progress, therefore reset the timeout; we do this * for read_select() to avoid that the periodic calls to user handlers * has to do it. */ - socket->ops->set_timeout(socket, 0); + socket->ops->set_timeout(socket, connection_state(0)); if (!socket->duplex) clear_handlers(socket->fd); @@ -851,7 +857,7 @@ read_select(struct socket *socket) rb = mem_realloc(rb, size); if (!rb) { - socket->ops->done(socket, S_OUT_OF_MEM); + socket->ops->done(socket, connection_state(S_OUT_OF_MEM)); return; } rb->freespace = size - sizeof(*rb) - rb->length; @@ -871,7 +877,7 @@ read_select(struct socket *socket) switch (rd) { #ifdef CONFIG_SSL case SOCKET_SSL_WANT_READ: - read_from_socket(socket, rb, S_TRANS, rb->done); + read_from_socket(socket, rb, connection_state(S_TRANS), rb->done); break; #endif case SOCKET_CANT_READ: @@ -881,15 +887,17 @@ read_select(struct socket *socket) break; } - errno = -S_CANT_READ; - /* Fall-through */ + socket->ops->retry(socket, connection_state(S_CANT_READ)); + break; case SOCKET_SYSCALL_ERROR: - socket->ops->retry(socket, -errno); + socket->ops->retry(socket, connection_state_for_errno(errno)); break; case SOCKET_INTERNAL_ERROR: - socket->ops->done(socket, -errno); + /* The global errno variable is used for passing + * internal connection_state error value. */ + socket->ops->done(socket, connection_state(errno)); break; default: @@ -910,7 +918,7 @@ alloc_read_buffer(struct socket *socket) rb = mem_calloc(1, RD_SIZE(rb, 0)); if (!rb) { - socket->ops->done(socket, S_OUT_OF_MEM); + socket->ops->done(socket, connection_state(S_OUT_OF_MEM)); return NULL; } @@ -925,13 +933,13 @@ alloc_read_buffer(struct socket *socket) void read_from_socket(struct socket *socket, struct read_buffer *buffer, - enum connection_state state, socket_read_T done) + struct connection_state state, socket_read_T done) { select_handler_T write_handler; buffer->done = done; - socket->ops->set_timeout(socket, 0); + socket->ops->set_timeout(socket, connection_state(0)); socket->ops->set_state(socket, state); if (socket->read_buffer && buffer != socket->read_buffer) @@ -953,12 +961,13 @@ read_response_from_socket(struct socket *socket) { struct read_buffer *rb = alloc_read_buffer(socket); - if (rb) read_from_socket(socket, rb, S_SENT, socket->read_done); + if (rb) read_from_socket(socket, rb, connection_state(S_SENT), + socket->read_done); } void request_from_socket(struct socket *socket, unsigned char *data, int datalen, - enum connection_state state, enum socket_state sock_state, + struct connection_state state, enum socket_state sock_state, socket_read_T read_done) { socket->read_done = read_done; diff --git a/src/network/socket.h b/src/network/socket.h index fc598ff19..0f085a68e 100644 --- a/src/network/socket.h +++ b/src/network/socket.h @@ -16,8 +16,8 @@ struct uri; /* Use internally for error return values. */ enum socket_error { - SOCKET_SYSCALL_ERROR = -1, /* Retry with -errno state. */ - SOCKET_INTERNAL_ERROR = -2, /* Stop with -errno state. */ + SOCKET_SYSCALL_ERROR = -1, /* Retry with connection_state_for_errno(errno). */ + SOCKET_INTERNAL_ERROR = -2, /* Stop with connection_state(errno). */ SOCKET_SSL_WANT_READ = -3, /* Try to read some more. */ SOCKET_CANT_READ = -4, /* Retry with S_CANT_READ state. */ SOCKET_CANT_WRITE = -5, /* Retry with S_CANT_WRITE state. */ @@ -39,7 +39,7 @@ enum socket_state { typedef void (*socket_read_T)(struct socket *, struct read_buffer *); typedef void (*socket_write_T)(struct socket *); typedef void (*socket_connect_T)(struct socket *); -typedef void (*socket_operation_T)(struct socket *, enum connection_state state); +typedef void (*socket_operation_T)(struct socket *, struct connection_state); struct socket_operations { /* Report change in the state of the socket. */ @@ -140,7 +140,7 @@ int get_pasv_socket(struct socket *ctrl_socket, struct sockaddr_storage *addr); /* Try to connect to the next available address or force the connection to retry * if all has already been tried. Updates the connection state to * @connection_state. */ -void connect_socket(struct socket *socket, enum connection_state state); +void connect_socket(struct socket *socket, struct connection_state state); /* Used by the SSL layer when negotiating. */ void dns_exception(struct socket *socket); @@ -151,17 +151,17 @@ void dns_exception(struct socket *socket); /* Reads data from @socket into @buffer. Calls @done each time new data is * ready. */ void read_from_socket(struct socket *socket, struct read_buffer *buffer, - enum connection_state state, socket_read_T done); + struct connection_state state, socket_read_T done); /* Writes @datalen bytes from @data buffer to the passed @socket. When all data * is written the @done callback will be called. */ void write_to_socket(struct socket *socket, unsigned char *data, int datalen, - enum connection_state state, socket_write_T write_done); + struct connection_state state, socket_write_T write_done); /* Send request and get response. */ void request_from_socket(struct socket *socket, unsigned char *data, int datalen, - enum connection_state state, enum socket_state sock_state, + struct connection_state state, enum socket_state sock_state, socket_read_T read_done); /* Initialize a read buffer. */ diff --git a/src/network/ssl/socket.c b/src/network/ssl/socket.c index 5e6eb4d8f..45b4b4a88 100644 --- a/src/network/ssl/socket.c +++ b/src/network/ssl/socket.c @@ -93,7 +93,7 @@ ssl_want_read(struct socket *socket) #ifdef CONFIG_GNUTLS if (get_opt_bool("connection.ssl.cert_verify") && gnutls_certificate_verify_peers(*((ssl_t *) socket->ssl))) { - socket->ops->retry(socket, S_SSL_ERROR); + socket->ops->retry(socket, connection_state(S_SSL_ERROR)); return; } #endif @@ -108,7 +108,7 @@ ssl_want_read(struct socket *socket) default: socket->no_tls = !socket->no_tls; - socket->ops->retry(socket, S_SSL_ERROR); + socket->ops->retry(socket, connection_state(S_SSL_ERROR)); } } @@ -119,7 +119,7 @@ ssl_connect(struct socket *socket) int ret; if (init_ssl_connection(socket) == S_SSL_ERROR) { - socket->ops->done(socket, S_SSL_ERROR); + socket->ops->done(socket, connection_state(S_SSL_ERROR)); return -1; } @@ -172,7 +172,7 @@ ssl_connect(struct socket *socket) switch (ret) { case SSL_ERROR_WANT_READ: case SSL_ERROR_WANT_READ2: - socket->ops->set_state(socket, S_SSL_NEG); + socket->ops->set_state(socket, connection_state(S_SSL_NEG)); set_handlers(socket->fd, (select_handler_T) ssl_want_read, NULL, (select_handler_T) dns_exception, socket); return -1; @@ -192,14 +192,14 @@ ssl_connect(struct socket *socket) socket->no_tls = !socket->no_tls; } - connect_socket(socket, S_SSL_ERROR); + connect_socket(socket, connection_state(S_SSL_ERROR)); return -1; } return 0; } -/* Return -1 on error, bytes written on success. */ +/* Return enum socket_error on error, bytes written on success. */ ssize_t ssl_write(struct socket *socket, unsigned char *data, int len) { @@ -221,15 +221,14 @@ ssl_write(struct socket *socket, unsigned char *data, int len) if (err == SSL_ERROR_SYSCALL) return SOCKET_SYSCALL_ERROR; - errno = -S_SSL_ERROR; - + errno = S_SSL_ERROR; return SOCKET_INTERNAL_ERROR; } return wr; } -/* Return -1 on error, rd or success. */ +/* Return enum socket_error on error, bytes read on success. */ ssize_t ssl_read(struct socket *socket, unsigned char *data, int len) { @@ -257,8 +256,7 @@ ssl_read(struct socket *socket, unsigned char *data, int len) if (err == SSL_ERROR_SYSCALL2) return SOCKET_SYSCALL_ERROR; - errno = -S_SSL_ERROR; - + errno = S_SSL_ERROR; return SOCKET_INTERNAL_ERROR; } diff --git a/src/network/state.c b/src/network/state.c index b5e4f0980..02f7b174d 100644 --- a/src/network/state.c +++ b/src/network/state.c @@ -142,7 +142,7 @@ static INIT_LIST_OF(struct strerror_val, strerror_buf); * It never returns NULL (if one changes that, be warn that * callers may not test for this condition) --Zas */ unsigned char * -get_state_message(enum connection_state state, struct terminal *term) +get_state_message(struct connection_state state, struct terminal *term) { unsigned char *e; struct strerror_val *s; @@ -153,13 +153,13 @@ get_state_message(enum connection_state state, struct terminal *term) int i; for (i = 0; msg_dsc[i].msg; i++) - if (msg_dsc[i].n == state) + if (msg_dsc[i].n == state.basic) return _(msg_dsc[i].msg, term); return unknown_error; } - e = (unsigned char *) strerror(-state); + e = (unsigned char *) strerror(state.syserr); if (!e || !*e) return unknown_error; len = strlen(e); diff --git a/src/network/state.h b/src/network/state.h index e5e443a62..d139d092b 100644 --- a/src/network/state.h +++ b/src/network/state.h @@ -1,6 +1,8 @@ #ifndef EL__NETWORK_STATE_H #define EL__NETWORK_STATE_H +#include "util/error.h" /* assert() */ + struct terminal; enum connection_priority { @@ -15,23 +17,18 @@ enum connection_priority { PRIORITIES, }; -/* Numbers < 0 and > -100000 are reserved for system errors reported via - * errno/strerror(), see session.c and connection.c for further information. */ -/* WARNING: an errno value <= -100000 may cause some bad things... */ -/* NOTE: Winsock errors are in range 10000..11004. Hence our abs. values are - * above this. */ - -#define is_system_error(state) (S_OK < (state) && (state) < S_WAIT) -#define is_in_result_state(state) ((state) < 0) -#define is_in_progress_state(state) ((state) >= 0) -#define is_in_connecting_state(state) (S_WAIT < (state) && (state) < S_TRANS) -#define is_in_transfering_state(state) ((state) >= S_TRANS) -#define is_in_queued_state(state) (is_in_connecting_state(state) || (state) == S_WAIT) +#define is_system_error(state) ((state).basic == S_ERRNO) +#define is_in_state(state,basic_) ((state).basic == (basic_)) +#define is_in_result_state(state) ((state).basic < 0) +#define is_in_progress_state(state) ((state).basic >= 0) +#define is_in_connecting_state(state) (S_WAIT < (state).basic && (state).basic < S_TRANS) +#define is_in_transfering_state(state) ((state).basic >= S_TRANS) +#define is_in_queued_state(state) (is_in_connecting_state(state) || (state).basic == S_WAIT) /* FIXME: Namespace clash with Windows headers. */ #undef S_OK -enum connection_state { +enum connection_basic_state { /* States >= 0 are used for connections still in progress. */ S_WAIT = 0, S_DNS, @@ -49,6 +46,7 @@ enum connection_state { /* State < 0 are used for the final result of a connection * (it's finished already and it ended up like this) */ + S_ERRNO = -1, S_OK = -100000, S_INTERRUPTED = -100001, S_EXCEPT = -100002, @@ -107,7 +105,44 @@ enum connection_state { S_BITTORRENT_BAD_URL = -100803, }; -unsigned char *get_state_message(enum connection_state state, struct terminal *term); +/** Either an ELinks internal status code or an error code from the + * system. Use connection_state() or connection_state_for_errno() + * to construct objects of this type. */ +struct connection_state { + /** An ELinks internal status code, or ::S_ERRNO if this + * structure holds a system error instead. */ + enum connection_basic_state basic; + + /** When #state is ::S_ERRNO, syserr is the saved value of + * errno. Otherwise, syserr should be 0. */ + int syserr; +}; + +unsigned char *get_state_message(struct connection_state state, struct terminal *term); void done_state_message(void); +static inline struct connection_state +connection_state(enum connection_basic_state basic) +{ + struct connection_state state = {0}; + + assert(basic != S_ERRNO); + if_assert_failed basic = S_INTERNAL; + + state.basic = basic; + return state; +} + +static inline struct connection_state +connection_state_for_errno(int syserr) +{ + struct connection_state state = {0}; + + /* read_encoded_file() can pass syserr==0 here, so don't + * assert otherwise. */ + state.basic = S_ERRNO; + state.syserr = syserr; + return state; +} + #endif diff --git a/src/protocol/about.c b/src/protocol/about.c index b3ca27a78..94ea1c61d 100644 --- a/src/protocol/about.c +++ b/src/protocol/about.c @@ -119,5 +119,5 @@ about_protocol_handler(struct connection *conn) } conn->cached = cached; - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); } diff --git a/src/protocol/bittorrent/bittorrent.c b/src/protocol/bittorrent/bittorrent.c index 9ce12b92e..344eefbbd 100644 --- a/src/protocol/bittorrent/bittorrent.c +++ b/src/protocol/bittorrent/bittorrent.c @@ -294,7 +294,7 @@ add_bittorrent_selection(struct uri *uri, int *selection, size_t size) static INIT_LIST_OF(struct bittorrent_message, bittorrent_messages); void -add_bittorrent_message(struct uri *uri, enum connection_state state, +add_bittorrent_message(struct uri *uri, struct connection_state state, struct string *string) { struct bittorrent_message *message; diff --git a/src/protocol/bittorrent/bittorrent.h b/src/protocol/bittorrent/bittorrent.h index d59b21265..d9c8f40c6 100644 --- a/src/protocol/bittorrent/bittorrent.h +++ b/src/protocol/bittorrent/bittorrent.h @@ -16,7 +16,7 @@ uint32_t get_bittorrent_peerwire_max_request_length(void); int *get_bittorrent_selection(struct uri *uri, size_t size); void add_bittorrent_selection(struct uri *uri, int *selection, size_t size); -void add_bittorrent_message(struct uri *uri, enum connection_state state, +void add_bittorrent_message(struct uri *uri, struct connection_state state, struct string *); #endif diff --git a/src/protocol/bittorrent/common.c b/src/protocol/bittorrent/common.c index a0a9ec1ca..eaeb5a1e2 100644 --- a/src/protocol/bittorrent/common.c +++ b/src/protocol/bittorrent/common.c @@ -335,13 +335,14 @@ bittorrent_fetch_callback(struct download *download, void *data) struct cache_entry *cached = download->cached; /* If the callback was removed we should shutdown ASAP. */ - if (!fetcher->callback || download->state == S_INTERRUPTED) { - if (download->state == S_INTERRUPTED) + if (!fetcher->callback || is_in_state(download->state, S_INTERRUPTED)) { + if (is_in_state(download->state, S_INTERRUPTED)) mem_free(fetcher); return; } - if (is_in_result_state(download->state) && download->state != S_OK) { + if (is_in_result_state(download->state) + && !is_in_state(download->state, S_OK)) { fetcher->callback(fetcher->data, download->state, NULL); if (fetcher->ref) *fetcher->ref = NULL; @@ -355,7 +356,7 @@ bittorrent_fetch_callback(struct download *download, void *data) if (cached->redirect && fetcher->redirects++ < MAX_REDIRECTS) { cancel_download(download, 0); - download->state = S_WAIT_REDIR; + download->state = connection_state(S_WAIT_REDIR); load_uri(cached->redirect, cached->uri, download, PRI_DOWNLOAD, CACHE_MODE_NORMAL, @@ -367,13 +368,13 @@ bittorrent_fetch_callback(struct download *download, void *data) if (is_in_progress_state(download->state)) return; - assert(download->state == S_OK); + assert(is_in_state(download->state, S_OK)); /* If the entry is chunked defragment it and grab the single, remaining * fragment. */ fragment = get_cache_fragment(cached); if (!fragment) { - fetcher->callback(fetcher->data, S_OUT_OF_MEM, NULL); + fetcher->callback(fetcher->data, connection_state(S_OUT_OF_MEM), NULL); if (fetcher->ref) *fetcher->ref = NULL; mem_free(fetcher); @@ -383,7 +384,7 @@ bittorrent_fetch_callback(struct download *download, void *data) response.source = fragment->data; response.length = fragment->length; - fetcher->callback(fetcher->data, S_OK, &response); + fetcher->callback(fetcher->data, connection_state(S_OK), &response); if (fetcher->delete) delete_cache_entry(cached); @@ -401,7 +402,7 @@ init_bittorrent_fetch(struct bittorrent_fetcher **fetcher_ref, fetcher = mem_calloc(1, sizeof(*fetcher)); if (!fetcher) { - callback(data, S_OUT_OF_MEM, NULL); + callback(data, connection_state(S_OUT_OF_MEM), NULL); return NULL; } diff --git a/src/protocol/bittorrent/common.h b/src/protocol/bittorrent/common.h index 26a863257..287f4ba38 100644 --- a/src/protocol/bittorrent/common.h +++ b/src/protocol/bittorrent/common.h @@ -68,7 +68,7 @@ struct bittorrent_message { LIST_HEAD(struct bittorrent_message); struct uri *uri; - enum connection_state state; + struct connection_state state; unsigned char string[1]; }; @@ -404,7 +404,7 @@ del_bittorrent_peer_request(struct bittorrent_peer_status *status, /* URI fetching: */ /* ************************************************************************** */ -typedef void (*bittorrent_fetch_callback_T)(void *, enum connection_state, struct string *); +typedef void (*bittorrent_fetch_callback_T)(void *, struct connection_state, struct string *); struct bittorrent_fetcher * init_bittorrent_fetch(struct bittorrent_fetcher **fetcher_ref, diff --git a/src/protocol/bittorrent/connection.c b/src/protocol/bittorrent/connection.c index 619e125c2..f15bfe84d 100644 --- a/src/protocol/bittorrent/connection.c +++ b/src/protocol/bittorrent/connection.c @@ -301,22 +301,22 @@ init_bittorrent_connection(struct connection *conn) void bittorrent_resume_callback(struct bittorrent_connection *bittorrent) { - enum connection_state state; + struct connection_state state; /* Failing to create the listening socket is fatal. */ state = init_bittorrent_listening_socket(bittorrent->conn); - if (state != S_OK) { + if (!is_in_state(state, S_OK)) { retry_connection(bittorrent->conn, state); return; } - set_connection_state(bittorrent->conn, S_CONN_TRACKER); + set_connection_state(bittorrent->conn, connection_state(S_CONN_TRACKER)); send_bittorrent_tracker_request(bittorrent->conn); } /* Metainfo file download callback */ static void -bittorrent_metainfo_callback(void *data, enum connection_state state, +bittorrent_metainfo_callback(void *data, struct connection_state state, struct string *response) { struct connection *conn = data; @@ -324,7 +324,7 @@ bittorrent_metainfo_callback(void *data, enum connection_state state, bittorrent->fetch = NULL; - if (state != S_OK) { + if (!is_in_state(state, S_OK)) { abort_connection(conn, state); return; } @@ -354,21 +354,22 @@ bittorrent_metainfo_callback(void *data, enum connection_state state, return; case BITTORRENT_STATE_CACHE_RESUME: - set_connection_state(bittorrent->conn, S_RESUME); + set_connection_state(bittorrent->conn, + connection_state(S_RESUME)); return; case BITTORRENT_STATE_OUT_OF_MEM: - state = S_OUT_OF_MEM; + state = connection_state(S_OUT_OF_MEM); break; default: - state = S_BITTORRENT_ERROR; + state = connection_state(S_BITTORRENT_ERROR); } break; } case BITTORRENT_STATE_OUT_OF_MEM: - state = S_OUT_OF_MEM; + state = connection_state(S_OUT_OF_MEM); break; case BITTORRENT_STATE_ERROR: @@ -378,7 +379,7 @@ bittorrent_metainfo_callback(void *data, enum connection_state state, * looking at the protocol header, however, direct usage of the * internal bittorrent: is at your own risk ... at least for * now. --jonas */ - state = S_BITTORRENT_METAINFO; + state = connection_state(S_BITTORRENT_METAINFO); } abort_connection(conn, state); @@ -393,7 +394,7 @@ bittorrent_protocol_handler(struct connection *conn) bittorrent = init_bittorrent_connection(conn); if (!bittorrent) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } @@ -401,11 +402,11 @@ bittorrent_protocol_handler(struct connection *conn) uri = get_uri(conn->uri->data, 0); if (!uri) { - abort_connection(conn, S_BITTORRENT_BAD_URL); + abort_connection(conn, connection_state(S_BITTORRENT_BAD_URL)); return; } - set_connection_state(conn, S_CONN); + set_connection_state(conn, connection_state(S_CONN)); set_connection_timeout(conn); conn->from = 0; diff --git a/src/protocol/bittorrent/dialogs.c b/src/protocol/bittorrent/dialogs.c index eec92c2ae..89a6ecb39 100644 --- a/src/protocol/bittorrent/dialogs.c +++ b/src/protocol/bittorrent/dialogs.c @@ -531,7 +531,7 @@ draw_bittorrent_piece_progress(struct download *download, struct terminal *term, } } - if (download->state == S_RESUME) { + if (is_in_state(download->state, S_RESUME)) { static unsigned char s[] = "????"; /* Reduce or enlarge at will. */ unsigned int slen = 0; int max = int_min(sizeof(s), width) - 1; @@ -587,9 +587,10 @@ bittorrent_message_dialog(struct session *ses, void *data) add_to_string(&string, ":\n\n"); } - if (message->state != S_OK) { + if (!is_in_state(message->state, S_OK)) { add_format_to_string(&string, "%s: %s", - get_state_message(S_BITTORRENT_TRACKER, ses->tab->term), + get_state_message(connection_state(S_BITTORRENT_TRACKER), + ses->tab->term), get_state_message(message->state, ses->tab->term)); } else { add_to_string(&string, message->string); @@ -686,7 +687,7 @@ tp_show_header(struct dialog_data *dlg_data, struct widget_data *widget_data) /* Build a dialog querying the user on how to handle a .torrent file. */ static void -bittorrent_query_callback(void *data, enum connection_state state, +bittorrent_query_callback(void *data, struct connection_state state, struct string *response) { /* [gettext_accelerator_context(.bittorrent_query_callback)] */ @@ -705,7 +706,7 @@ bittorrent_query_callback(void *data, enum connection_state state, struct string msg; int files; - if (state != S_OK) + if (!is_in_state(state, S_OK)) return; /* This should never happen, since setup_download_handler() should make @@ -739,7 +740,8 @@ bittorrent_query_callback(void *data, enum connection_state state, done_string(&filename); if (parse_bittorrent_metafile(&meta, response) != BITTORRENT_STATE_OK) { - print_error_dialog(type_query->ses, S_BITTORRENT_METAINFO, + print_error_dialog(type_query->ses, + connection_state(S_BITTORRENT_METAINFO), type_query->uri, PRI_CANCEL); tp_cancel(type_query); done_string(&msg); diff --git a/src/protocol/bittorrent/peerconnect.c b/src/protocol/bittorrent/peerconnect.c index ba93982cc..8db721116 100644 --- a/src/protocol/bittorrent/peerconnect.c +++ b/src/protocol/bittorrent/peerconnect.c @@ -67,7 +67,7 @@ find_bittorrent_connection(bittorrent_id_T info_hash) static void check_bittorrent_peer_blacklisting(struct bittorrent_peer_connection *peer, - enum connection_state state) + struct connection_state state) { enum bittorrent_blacklist_flags flags = BITTORRENT_BLACKLIST_NONE; @@ -75,21 +75,25 @@ check_bittorrent_peer_blacklisting(struct bittorrent_peer_connection *peer, || !get_opt_bool("protocol.http.bugs.allow_blacklist")) return; - switch (state) { - case -ECONNREFUSED: - case -ENETUNREACH: - flags |= BITTORRENT_BLACKLIST_PEER_POOL; - break; - - case S_CANT_WRITE: - case S_CANT_READ: - if (!peer->local.handshake - || !peer->remote.handshake) + if (is_system_error(state)) { + switch (state.syserr) { + case ECONNREFUSED: + case ENETUNREACH: flags |= BITTORRENT_BLACKLIST_PEER_POOL; - break; + break; + } + } else { + switch (state.basic) { + case S_CANT_WRITE: + case S_CANT_READ: + if (!peer->local.handshake + || !peer->remote.handshake) + flags |= BITTORRENT_BLACKLIST_PEER_POOL; + break; - default: - break; + default: + break; + } } if (flags != BITTORRENT_BLACKLIST_NONE) { @@ -137,30 +141,30 @@ set_bittorrent_peer_connection_timeout(struct bittorrent_peer_connection *peer) * S_DMS (while looking up the host) then moves to S_CONN (while connecting), * and should hopefully become S_TRANS (while transfering). Note, state can hold * both internally defined connection states as described above and errno - * values, such as ECONNREFUSED. The errno values are passed negative so in the - * previous example the errno would be passed as -ECONNREFUSED. */ + * values, such as ECONNREFUSED. */ static void -set_bittorrent_socket_state(struct socket *socket, enum connection_state state) +set_bittorrent_socket_state(struct socket *socket, struct connection_state state) { struct bittorrent_peer_connection *peer = socket->conn; - if (state == S_TRANS && peer->bittorrent) - set_connection_state(peer->bittorrent->conn, S_TRANS); + if (is_in_state(state, S_TRANS) && peer->bittorrent) + set_connection_state(peer->bittorrent->conn, + connection_state(S_TRANS)); } /* Called when progress is made such as when the select() loop detects and * schedules reads and writes. The state variable must be ignored. */ static void -set_bittorrent_socket_timeout(struct socket *socket, enum connection_state state) +set_bittorrent_socket_timeout(struct socket *socket, struct connection_state state) { - assert(state == 0); + assert(is_in_state(state, 0)); set_bittorrent_peer_connection_timeout(socket->conn); } /* Called when a non-fatal error condition has appeared, i.e. the condition is * caused by some internal or local system error or simply a timeout. */ static void -retry_bittorrent_socket(struct socket *socket, enum connection_state state) +retry_bittorrent_socket(struct socket *socket, struct connection_state state) { struct bittorrent_peer_connection *peer = socket->conn; @@ -177,7 +181,7 @@ retry_bittorrent_socket(struct socket *socket, enum connection_state state) /* Called when a fatal and unrecoverable error condition has appeared, such as a * DNS query failed. */ static void -done_bittorrent_socket(struct socket *socket, enum connection_state state) +done_bittorrent_socket(struct socket *socket, struct connection_state state) { struct bittorrent_peer_connection *peer = socket->conn; @@ -344,7 +348,7 @@ accept_bittorrent_peer_connection(void *____) buffer = alloc_read_buffer(peer->socket); if (!buffer) return; - read_from_socket(peer->socket, buffer, S_TRANS, + read_from_socket(peer->socket, buffer, connection_state(S_TRANS), read_bittorrent_peer_handshake); add_to_list(bittorrent_peer_connections, peer); @@ -352,7 +356,7 @@ accept_bittorrent_peer_connection(void *____) /* Based on network/socket.c:get_pasv_socket() but modified to try and bind to a * port range instead of any port. */ -enum connection_state +struct connection_state init_bittorrent_listening_socket(struct connection *conn) { struct bittorrent_connection *bittorrent = conn->info; @@ -366,7 +370,7 @@ init_bittorrent_listening_socket(struct connection *conn) /* Has the socket already been initialized? */ if (!list_is_singleton(bittorrent_connections)) - return S_OK; + return connection_state(S_OK); /* We could have bailed out from an earlier attempt. */ if (bittorrent_socket != -1) @@ -374,12 +378,12 @@ init_bittorrent_listening_socket(struct connection *conn) bittorrent_socket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); if (bittorrent_socket < 0) - return -errno; + return connection_state_for_errno(errno); /* Set it non-blocking */ if (set_nonblocking_fd(bittorrent_socket) < 0) - return -errno; + return connection_state_for_errno(errno); /* Bind it to some port */ @@ -392,11 +396,11 @@ init_bittorrent_listening_socket(struct connection *conn) /* Repeatedly try the configured port range. */ while (bind(bittorrent_socket, (struct sockaddr *) &addr, sizeof(addr))) { if (errno != EADDRINUSE) - return -errno; + return connection_state_for_errno(errno); /* If all ports was in use fail with EADDRINUSE. */ if (++port > max_port) - return -errno; + return connection_state_for_errno(errno); memset(&addr, 0, sizeof(addr)); addr.sin_port = htons(port); @@ -407,20 +411,20 @@ init_bittorrent_listening_socket(struct connection *conn) memset(&addr2, 0, sizeof(addr2)); len = sizeof(addr2); if (getsockname(bittorrent_socket, (struct sockaddr *) &addr2, &len)) - return -errno; + return connection_state_for_errno(errno); bittorrent->port = ntohs(addr2.sin_port); /* Go listen */ if (listen(bittorrent_socket, LISTEN_BACKLOG)) - return -errno; + return connection_state_for_errno(errno); set_ip_tos_throughput(bittorrent_socket); set_handlers(bittorrent_socket, accept_bittorrent_peer_connection, NULL, NULL, NULL); - return S_OK; + return connection_state(S_OK); } void diff --git a/src/protocol/bittorrent/peerconnect.h b/src/protocol/bittorrent/peerconnect.h index 1e7df36ae..08b695c21 100644 --- a/src/protocol/bittorrent/peerconnect.h +++ b/src/protocol/bittorrent/peerconnect.h @@ -8,7 +8,7 @@ struct connection; /* Sets up and tears down the peer listening socket. */ -enum connection_state init_bittorrent_listening_socket(struct connection *conn); +struct connection_state init_bittorrent_listening_socket(struct connection *conn); void done_bittorrent_listening_socket(struct connection *conn); void done_bittorrent_peer_connection(struct bittorrent_peer_connection *peer); diff --git a/src/protocol/bittorrent/peerwire.c b/src/protocol/bittorrent/peerwire.c index 35bcc4546..f631faff6 100644 --- a/src/protocol/bittorrent/peerwire.c +++ b/src/protocol/bittorrent/peerwire.c @@ -349,7 +349,8 @@ do_send_bittorrent_peer_message(struct bittorrent_peer_connection *peer, } write_to_socket(peer->socket, string.source, string.length, - S_TRANS, sent_bittorrent_peer_message); + connection_state(S_TRANS), + sent_bittorrent_peer_message); done_string(&string); @@ -658,7 +659,8 @@ read_bittorrent_peer_data(struct socket *socket, struct read_buffer *buffer) break; case BITTORRENT_STATE_OUT_OF_MEM: - abort_connection(peer->bittorrent->conn, S_OUT_OF_MEM); + abort_connection(peer->bittorrent->conn, + connection_state(S_OUT_OF_MEM)); return; case BITTORRENT_STATE_ERROR: @@ -669,7 +671,8 @@ read_bittorrent_peer_data(struct socket *socket, struct read_buffer *buffer) } /* Shutdown on fatal errors! */ - abort_connection(peer->bittorrent->conn, -write_errno); + abort_connection(peer->bittorrent->conn, + connection_state_for_errno(write_errno)); return; } @@ -710,7 +713,7 @@ sent_bittorrent_peer_handshake(struct socket *socket) send_bittorrent_peer_message(peer, BITTORRENT_MESSAGE_BITFIELD); } - read_from_socket(peer->socket, buffer, S_TRANS, + read_from_socket(peer->socket, buffer, connection_state(S_TRANS), read_bittorrent_peer_data); } @@ -763,7 +766,8 @@ send_bittorrent_peer_handshake(struct socket *socket) * and we might want to hold on to the old buffer if the peer ID of the * handshake was not read. */ write_to_socket(peer->socket, handshake, sizeof(handshake), - S_TRANS, sent_bittorrent_peer_handshake); + connection_state(S_TRANS), + sent_bittorrent_peer_handshake); } #if 0 @@ -935,7 +939,8 @@ do_read_bittorrent_peer_handshake(struct socket *socket, struct read_buffer *buf break; } - read_from_socket(peer->socket, buffer, S_TRANS, + read_from_socket(peer->socket, buffer, + connection_state(S_TRANS), read_bittorrent_peer_handshake); break; @@ -945,7 +950,8 @@ do_read_bittorrent_peer_handshake(struct socket *socket, struct read_buffer *buf case BITTORRENT_PEER_HANDSHAKE_INCOMPLETE: /* The whole handshake was not read so wait for more. */ - read_from_socket(peer->socket, buffer, S_TRANS, + read_from_socket(peer->socket, buffer, + connection_state(S_TRANS), read_bittorrent_peer_handshake); break; } diff --git a/src/protocol/bittorrent/tracker.c b/src/protocol/bittorrent/tracker.c index fc7117087..6ca91e244 100644 --- a/src/protocol/bittorrent/tracker.c +++ b/src/protocol/bittorrent/tracker.c @@ -60,7 +60,7 @@ set_bittorrent_tracker_interval(struct connection *conn) /* XXX: The data pointer may be NULL when doing event=stopped because no * connection is attached anymore. */ static void -bittorrent_tracker_callback(void *data, enum connection_state state, +bittorrent_tracker_callback(void *data, struct connection_state state, struct string *response) { struct connection *conn = data; @@ -75,12 +75,12 @@ bittorrent_tracker_callback(void *data, enum connection_state state, /* FIXME: We treat any error as fatal here, however, it might be better * to relax that and allow a few errors before ending the connection. */ - if (state != S_OK) { - if (state == S_INTERRUPTED) + if (!is_in_state(state, S_OK)) { + if (is_in_state(state, S_INTERRUPTED)) return; bittorrent->tracker.failed = 1; add_bittorrent_message(conn->uri, state, NULL); - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); return; } @@ -102,16 +102,17 @@ bittorrent_tracker_callback(void *data, enum connection_state state, return; case BITTORRENT_STATE_OUT_OF_MEM: - state = S_OUT_OF_MEM; + state = connection_state(S_OUT_OF_MEM); break; case BITTORRENT_STATE_REQUEST_FAILURE: - add_bittorrent_message(conn->uri, S_OK, response); - state = S_OK; + add_bittorrent_message(conn->uri, connection_state(S_OK), + response); + state = connection_state(S_OK); break; default: - state = S_BITTORRENT_TRACKER; + state = connection_state(S_BITTORRENT_TRACKER); } abort_connection(conn, state); @@ -158,7 +159,8 @@ do_send_bittorrent_tracker_request(struct connection *conn) if (!init_string(&request)) { done_string(&request); if (!stopped) - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, + connection_state(S_OUT_OF_MEM)); return; } @@ -169,7 +171,8 @@ do_send_bittorrent_tracker_request(struct connection *conn) if (!uri) { done_string(&request); if (!stopped) - abort_connection(conn, S_BITTORRENT_ERROR); + abort_connection(conn, + connection_state(S_BITTORRENT_ERROR)); return; } @@ -246,7 +249,8 @@ do_send_bittorrent_tracker_request(struct connection *conn) done_string(&request); if (!uri) { if (!stopped) - abort_connection(conn, S_BITTORRENT_ERROR); + abort_connection(conn, + connection_state(S_BITTORRENT_ERROR)); return; } diff --git a/src/protocol/common.c b/src/protocol/common.c index 41807e132..ebf980829 100644 --- a/src/protocol/common.c +++ b/src/protocol/common.c @@ -43,7 +43,7 @@ close_all_non_term_fd(void) close(n); } -enum connection_state +struct connection_state init_directory_listing(struct string *page, struct uri *uri) { struct string dirpath = NULL_STRING; @@ -151,5 +151,7 @@ out_of_memory: done_string(&decoded); done_string(&location); - return page->length > 0 ? S_OK : S_OUT_OF_MEM; + return page->length > 0 + ? connection_state(S_OK) + : connection_state(S_OUT_OF_MEM); } diff --git a/src/protocol/common.h b/src/protocol/common.h index 116541850..7dc259bb5 100644 --- a/src/protocol/common.h +++ b/src/protocol/common.h @@ -9,7 +9,7 @@ struct uri; /* Close all non-terminal file descriptors. */ void close_all_non_term_fd(void); -enum connection_state +struct connection_state init_directory_listing(struct string *page, struct uri *uri); #endif diff --git a/src/protocol/data.c b/src/protocol/data.c index c783239e1..42dea5aaf 100644 --- a/src/protocol/data.c +++ b/src/protocol/data.c @@ -120,7 +120,7 @@ data_protocol_handler(struct connection *conn) int base64 = 0; if (!cached) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } @@ -128,7 +128,7 @@ data_protocol_handler(struct connection *conn) data_start = parse_data_protocol_header(conn, &base64); if (!data_start) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } @@ -136,7 +136,7 @@ data_protocol_handler(struct connection *conn) * it. */ data = memacpy(data_start, uri->datalen - (data_start - uri->data)); if (!data) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } @@ -144,7 +144,7 @@ data_protocol_handler(struct connection *conn) unsigned char *decoded = base64_encode(data); if (!decoded) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } @@ -163,5 +163,5 @@ data_protocol_handler(struct connection *conn) mem_free(data); - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); } diff --git a/src/protocol/file/cgi.c b/src/protocol/file/cgi.c index 8cb02bb9d..c8f3a41fe 100644 --- a/src/protocol/file/cgi.c +++ b/src/protocol/file/cgi.c @@ -77,7 +77,8 @@ close_pipe_and_read(struct socket *data_socket) data_socket->fd = -1; conn->socket->state = SOCKET_END_ONCLOSE; - read_from_socket(conn->socket, rb, S_SENT, http_got_header); + read_from_socket(conn->socket, rb, connection_state(S_SENT), + http_got_header); } static void @@ -91,7 +92,7 @@ send_post_data(struct connection *conn) int n = 0; if (!init_string(&data)) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } postend = strchr(post, '\n'); @@ -125,7 +126,7 @@ send_post_data(struct connection *conn) * and an assertion would fail in write_to_socket. */ if (data.length) write_to_socket(conn->data_socket, data.source, data.length, - S_SENT, close_pipe_and_read); + connection_state(S_SENT), close_pipe_and_read); else close_pipe_and_read(conn->data_socket); @@ -309,7 +310,7 @@ execute_cgi(struct connection *conn) int scriptlen; struct stat buf; pid_t pid; - enum connection_state state = S_OK; + struct connection_state state = connection_state(S_OK); int pipe_read[2], pipe_write[2]; if (!get_opt_bool("protocol.file.cgi.policy")) return 1; @@ -321,7 +322,7 @@ execute_cgi(struct connection *conn) script = get_uri_string(conn->uri, URI_PATH); if (!script) { - state = S_OUT_OF_MEM; + state = connection_state(S_OUT_OF_MEM); goto end2; } decode_uri(script); @@ -353,13 +354,13 @@ execute_cgi(struct connection *conn) } if (c_pipe(pipe_read) || c_pipe(pipe_write)) { - state = -errno; + state = connection_state_for_errno(errno); goto end1; } pid = fork(); if (pid < 0) { - state = -errno; + state = connection_state_for_errno(errno); goto end0; } if (!pid) { /* CGI script */ diff --git a/src/protocol/file/file.c b/src/protocol/file/file.c index 0676c1c2f..833ed8bc5 100644 --- a/src/protocol/file/file.c +++ b/src/protocol/file/file.c @@ -174,33 +174,33 @@ add_dir_entries(struct directory_entry *entries, unsigned char *dirpath, /* Generates an HTML page listing the content of @directory with the path * @dirpath. */ /* Returns a connection state. S_OK if all is well. */ -static inline enum connection_state +static inline struct connection_state list_directory(struct connection *conn, unsigned char *dirpath, struct string *page) { int show_hidden_files = get_opt_bool("protocol.file.show_hidden_files"); struct directory_entry *entries; - enum connection_state state; + struct connection_state state; errno = 0; entries = get_directory_entries(dirpath, show_hidden_files); if (!entries) { - if (errno) return -errno; - return S_OUT_OF_MEM; + if (errno) return connection_state_for_errno(errno); + return connection_state(S_OUT_OF_MEM); } state = init_directory_listing(page, conn->uri); - if (state != S_OK) - return S_OUT_OF_MEM; + if (!is_in_state(state, S_OK)) + return connection_state(S_OUT_OF_MEM); add_dir_entries(entries, dirpath, page); if (!add_to_string(page, "\n
\n\n\n")) { done_string(page); - return S_OUT_OF_MEM; + return connection_state(S_OUT_OF_MEM); } - return S_OK; + return connection_state(S_OK); } @@ -215,13 +215,14 @@ file_protocol_handler(struct connection *connection) { unsigned char *redirect_location = NULL; struct string page, name; - enum connection_state state; + struct connection_state state; int set_dir_content_type = 0; if (get_cmd_opt_bool("anonymous")) { if (strcmp(connection->uri->string, "file:///dev/stdin") || isatty(STDIN_FILENO)) { - abort_connection(connection, S_FILE_ANONYMOUS); + abort_connection(connection, + connection_state(S_FILE_ANONYMOUS)); return; } } @@ -239,7 +240,7 @@ file_protocol_handler(struct connection *connection) if (!init_string(&name) || !add_uri_to_string(&name, connection->uri, URI_PATH)) { done_string(&name); - abort_connection(connection, S_OUT_OF_MEM); + abort_connection(connection, connection_state(S_OUT_OF_MEM)); return; } @@ -254,7 +255,7 @@ file_protocol_handler(struct connection *connection) * directory separator. */ if (name.source[0] && !dir_sep(name.source[name.length - 1])) { redirect_location = STRING_DIR_SEP; - state = S_OK; + state = connection_state(S_OK); } else { state = list_directory(connection, name.source, &page); set_dir_content_type = 1; @@ -268,7 +269,7 @@ file_protocol_handler(struct connection *connection) done_string(&name); - if (state == S_OK) { + if (is_in_state(state, S_OK)) { struct cache_entry *cached; /* Try to add fragment data to the connection cache if either @@ -276,11 +277,11 @@ file_protocol_handler(struct connection *connection) cached = connection->cached = get_cache_entry(connection->uri); if (!connection->cached) { if (!redirect_location) done_string(&page); - state = S_OUT_OF_MEM; + state = connection_state(S_OUT_OF_MEM); } else if (redirect_location) { if (!redirect_cache(cached, redirect_location, 1, 0)) - state = S_OUT_OF_MEM; + state = connection_state(S_OUT_OF_MEM); } else { add_fragment(cached, 0, page.source, page.length); @@ -300,7 +301,7 @@ file_protocol_handler(struct connection *connection) /* Not so gracefully handle failed memory * allocation. */ if (!head) - state = S_OUT_OF_MEM; + state = connection_state(S_OUT_OF_MEM); /* Setup directory listing for viewing. */ mem_free_set(&cached->head, head); diff --git a/src/protocol/finger/finger.c b/src/protocol/finger/finger.c index 6f09b7287..c26069216 100644 --- a/src/protocol/finger/finger.c +++ b/src/protocol/finger/finger.c @@ -35,13 +35,13 @@ finger_get_response(struct socket *socket, struct read_buffer *rb) int l; if (!cached) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } conn->cached = cached; if (socket->state == SOCKET_CLOSED) { - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); return; } @@ -53,7 +53,8 @@ finger_get_response(struct socket *socket, struct read_buffer *rb) conn->from += l; kill_buffer_data(rb, l); - read_from_socket(conn->socket, rb, S_TRANS, finger_get_response); + read_from_socket(conn->socket, rb, connection_state(S_TRANS), + finger_get_response); } static void @@ -70,7 +71,8 @@ finger_send_request(struct socket *socket) add_bytes_to_string(&req, conn->uri->user, conn->uri->userlen); } add_crlf_to_string(&req); - request_from_socket(socket, req.source, req.length, S_SENT, + request_from_socket(socket, req.source, req.length, + connection_state(S_SENT), SOCKET_END_ONCLOSE, finger_get_response); done_string(&req); } diff --git a/src/protocol/fsp/fsp.c b/src/protocol/fsp/fsp.c index cd62fbf85..a46cc8d31 100644 --- a/src/protocol/fsp/fsp.c +++ b/src/protocol/fsp/fsp.c @@ -74,11 +74,11 @@ struct module fsp_protocol_module = struct_module( * * - If an error occurs, the child process writes "text/x-error" * without newline to stderr, and an error code and a newline to - * stdout. The error code is either from errno or a negated value - * from enum connection_state, e.g. -S_OUT_OF_MEM. In particular, - * EPERM causes the parent process to prompt for username and - * password. (In this, fsplib differs from libsmbclient, which uses - * EACCES if authentication fails.) + * stdout. The error code is either "S" followed by errno or "I" + * followed by enum connection_basic_state. In particular, EPERM + * causes the parent process to prompt for username and password. + * (In this, fsplib differs from libsmbclient, which uses EACCES if + * authentication fails.) * * - If the resource is a regular file, the child process writes the * estimated length of the file (in bytes) and a newline to stderr, @@ -103,9 +103,12 @@ struct module fsp_protocol_module = struct_module( * stdout fails for directory listing like we do for file fetching. */ static void -fsp_error(int error) +fsp_error(struct connection_state error) { - printf("%d\n", error); + if (is_system_error(error)) + printf("S%d\n", (int) error.syserr); + else + printf("I%d\n", (int) error.basic); fprintf(stderr, "text/x-error"); /* In principle, this should perhaps call fsp_close_session to * make the server accept any key from the next client process @@ -215,13 +218,13 @@ fsp_directory(FSP_SESSION *ses, struct uri *uri) unsigned char dircolor[8] = ""; if (!data) - fsp_error(-S_OUT_OF_MEM); + fsp_error(connection_state(S_OUT_OF_MEM)); decode_uri(data); - if (init_directory_listing(&buf, uri) != S_OK) - fsp_error(-S_OUT_OF_MEM); + if (!is_in_state(init_directory_listing(&buf, uri), S_OK)) + fsp_error(connection_state(S_OUT_OF_MEM)); dir = fsp_opendir(ses, data); - if (!dir) fsp_error(errno); + if (!dir) fsp_error(connection_state_for_errno(errno)); fprintf(stderr, "text/html"); fclose(stderr); @@ -275,7 +278,7 @@ do_fsp(struct connection *conn) } ses = fsp_open_session(host, port, password); - if (!ses) fsp_error(errno); + if (!ses) fsp_error(connection_state_for_errno(errno)); /* fsplib 0.8 ABI depends on _FILE_OFFSET_BITS * https://sourceforge.net/tracker/index.php?func=detail&aid=1674729&group_id=93841&atid=605738 @@ -295,7 +298,7 @@ do_fsp(struct connection *conn) * sb.st_size really needs to be filled, but filling the rest * too helps viewing the data with a debugger.) */ memset(&sb, 0xAA, sizeof(sb)); - if (fsp_stat(ses, data, &sb)) fsp_error(errno); + if (fsp_stat(ses, data, &sb)) fsp_error(connection_state_for_errno(errno)); if (S_ISDIR(sb.st_mode)) { fsp_directory(ses, uri); @@ -305,7 +308,7 @@ do_fsp(struct connection *conn) int r; if (!file) { - fsp_error(errno); + fsp_error(connection_state_for_errno(errno)); } #if SIZEOF_OFF_T >= 8 @@ -359,7 +362,7 @@ static void prompt_username_pw(struct connection *conn) { add_auth_entry(conn->uri, "FSP", NULL, NULL, 0); - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); } static void @@ -367,10 +370,10 @@ fsp_got_error(struct socket *socket, struct read_buffer *rb) { int len = rb->length; struct connection *conn = socket->conn; - int error; + struct connection_state error; if (len < 0) { - abort_connection(conn, -errno); + abort_connection(conn, connection_state_for_errno(errno)); return; } @@ -380,20 +383,28 @@ fsp_got_error(struct socket *socket, struct read_buffer *rb) * pipe. */ assert(rb->freespace >= 1); if_assert_failed { - abort_connection(conn, S_INTERNAL); + abort_connection(conn, connection_state(S_INTERNAL)); return; } rb->data[len] = '\0'; - error = atoi(rb->data); - kill_buffer_data(rb, len); - switch (error) { - case EPERM: - prompt_username_pw(conn); + switch (rb->data[0]) { + case 'S': + error = connection_state_for_errno(atoi(rb->data + 1)); + break; + case 'I': + error = connection_state(atoi(rb->data + 1)); break; default: - abort_connection(conn, -error); + ERROR("malformed error code: %s", rb->data); + error = connection_state(S_INTERNAL); break; } + kill_buffer_data(rb, len); + + if (is_system_error(error) && error.syserr == EPERM) + prompt_username_pw(conn); + else + abort_connection(conn, error); } static void @@ -403,12 +414,12 @@ fsp_got_data(struct socket *socket, struct read_buffer *rb) struct connection *conn = socket->conn; if (len < 0) { - abort_connection(conn, -errno); + abort_connection(conn, connection_state_for_errno(errno)); return; } if (!len) { - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); return; } @@ -419,7 +430,7 @@ fsp_got_data(struct socket *socket, struct read_buffer *rb) conn->from += len; kill_buffer_data(rb, len); - read_from_socket(socket, rb, S_TRANS, fsp_got_data); + read_from_socket(socket, rb, connection_state(S_TRANS), fsp_got_data); } static void @@ -438,7 +449,7 @@ fsp_got_header(struct socket *socket, struct read_buffer *rb) * and assume abort_connection will do them?) */ close_socket(socket); close_socket(conn->data_socket); - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } socket->state = SOCKET_END_ONCLOSE; @@ -461,7 +472,7 @@ fsp_got_header(struct socket *socket, struct read_buffer *rb) /* avoid read from socket error */ if (!conn->est_length) { - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); return; } } @@ -476,15 +487,17 @@ fsp_got_header(struct socket *socket, struct read_buffer *rb) if (!buf) { close_socket(socket); close_socket(conn->data_socket); - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } if (error) { mem_free_set(&conn->cached->content_type, stracpy("text/html")); - read_from_socket(conn->data_socket, buf, S_CONN, fsp_got_error); + read_from_socket(conn->data_socket, buf, + connection_state(S_CONN), fsp_got_error); } else { - read_from_socket(conn->data_socket, buf, S_CONN, fsp_got_data); + read_from_socket(conn->data_socket, buf, + connection_state(S_CONN), fsp_got_data); } } @@ -503,7 +516,7 @@ fsp_protocol_handler(struct connection *conn) if (fsp_pipe[1] >= 0) close(fsp_pipe[1]); if (header_pipe[0] >= 0) close(header_pipe[0]); if (header_pipe[1] >= 0) close(header_pipe[1]); - abort_connection(conn, -s_errno); + abort_connection(conn, connection_state_for_errno(s_errno)); return; } conn->from = 0; @@ -518,7 +531,7 @@ fsp_protocol_handler(struct connection *conn) close(fsp_pipe[1]); close(header_pipe[0]); close(header_pipe[1]); - retry_connection(conn, -s_errno); + retry_connection(conn, connection_state_for_errno(s_errno)); return; } @@ -556,9 +569,10 @@ fsp_protocol_handler(struct connection *conn) if (!buf2) { close_socket(conn->data_socket); close_socket(conn->socket); - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } - read_from_socket(conn->socket, buf2, S_CONN, fsp_got_header); + read_from_socket(conn->socket, buf2, + connection_state(S_CONN), fsp_got_header); } } diff --git a/src/protocol/ftp/ftp.c b/src/protocol/ftp/ftp.c index eefe8b1a1..ca5b6f4a8 100644 --- a/src/protocol/ftp/ftp.c +++ b/src/protocol/ftp/ftp.c @@ -119,7 +119,7 @@ struct ftp_connection_info { /* Prototypes */ static void ftp_login(struct socket *); -static void ftp_send_retr_req(struct connection *, int); +static void ftp_send_retr_req(struct connection *, struct connection_state); static void ftp_got_info(struct socket *, struct read_buffer *); static void ftp_got_user_info(struct socket *, struct read_buffer *); static void ftp_pass(struct connection *); @@ -127,7 +127,7 @@ static void ftp_pass_info(struct socket *, struct read_buffer *); static void ftp_retr_file(struct socket *, struct read_buffer *); static void ftp_got_final_response(struct socket *, struct read_buffer *); static void got_something_from_data_connection(struct connection *); -static void ftp_end_request(struct connection *, enum connection_state); +static void ftp_end_request(struct connection *, struct connection_state); static struct ftp_connection_info *add_file_cmd_to_str(struct connection *); static void ftp_data_accept(struct connection *conn); @@ -276,13 +276,14 @@ ftp_protocol_handler(struct connection *conn) conn->cache_mode >= CACHE_MODE_FORCE_RELOAD); } else { - ftp_send_retr_req(conn, S_SENT); + ftp_send_retr_req(conn, connection_state(S_SENT)); } } /* Send command, set connection state and free cmd string. */ static void -send_cmd(struct connection *conn, struct string *cmd, void *callback, int state) +send_cmd(struct connection *conn, struct string *cmd, void *callback, + struct connection_state state) { request_from_socket(conn->socket, cmd->source, cmd->length, state, SOCKET_RETRY_ONCLOSE, callback); @@ -308,20 +309,20 @@ prompt_username_pw(struct connection *conn) if (!conn->cached) { conn->cached = get_cache_entry(conn->uri); if (!conn->cached) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } } mem_free_set(&conn->cached->content_type, stracpy("text/html")); if (!conn->cached->content_type) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } add_auth_entry(conn->uri, "FTP Login", NULL, NULL, 0); - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); } /* Send USER command. */ @@ -335,7 +336,7 @@ ftp_login(struct socket *socket) auth = find_auth(conn->uri); if (!init_string(&cmd)) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } @@ -353,7 +354,7 @@ ftp_login(struct socket *socket) } add_crlf_to_string(&cmd); - send_cmd(conn, &cmd, (void *) ftp_got_info, S_SENT); + send_cmd(conn, &cmd, (void *) ftp_got_info, connection_state(S_SENT)); } /* Parse connection response. */ @@ -364,7 +365,7 @@ ftp_got_info(struct socket *socket, struct read_buffer *rb) int response = get_ftp_response(conn, rb, 0, NULL); if (response == -1) { - abort_connection(conn, S_FTP_ERROR); + abort_connection(conn, connection_state(S_FTP_ERROR)); return; } @@ -380,7 +381,7 @@ ftp_got_info(struct socket *socket, struct read_buffer *rb) if (response != 220) { /* TODO? Retry in case of ... ?? */ - retry_connection(conn, S_FTP_UNAVAIL); + retry_connection(conn, connection_state(S_FTP_UNAVAIL)); return; } @@ -396,7 +397,7 @@ ftp_got_user_info(struct socket *socket, struct read_buffer *rb) int response = get_ftp_response(conn, rb, 0, NULL); if (response == -1) { - abort_connection(conn, S_FTP_ERROR); + abort_connection(conn, connection_state(S_FTP_ERROR)); return; } @@ -426,12 +427,12 @@ ftp_got_user_info(struct socket *socket, struct read_buffer *rb) * non-RFC compliant servers may return even something other than 421. * --Zas */ if (response >= 400) { - abort_connection(conn, S_FTP_UNAVAIL); + abort_connection(conn, connection_state(S_FTP_UNAVAIL)); return; } if (response == 230) { - ftp_send_retr_req(conn, S_GETH); + ftp_send_retr_req(conn, connection_state(S_GETH)); return; } @@ -448,7 +449,7 @@ ftp_pass(struct connection *conn) auth = find_auth(conn->uri); if (!init_string(&cmd)) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } @@ -470,7 +471,7 @@ ftp_pass(struct connection *conn) } add_crlf_to_string(&cmd); - send_cmd(conn, &cmd, (void *) ftp_pass_info, S_LOGIN); + send_cmd(conn, &cmd, (void *) ftp_pass_info, connection_state(S_LOGIN)); } /* Parse PASS command response. */ @@ -481,12 +482,13 @@ ftp_pass_info(struct socket *socket, struct read_buffer *rb) int response = get_ftp_response(conn, rb, 0, NULL); if (response == -1) { - abort_connection(conn, S_FTP_ERROR); + abort_connection(conn, connection_state(S_FTP_ERROR)); return; } if (!response) { - read_from_socket(conn->socket, rb, S_LOGIN, ftp_pass_info); + read_from_socket(conn->socket, rb, connection_state(S_LOGIN), + ftp_pass_info); return; } @@ -508,11 +510,11 @@ ftp_pass_info(struct socket *socket, struct read_buffer *rb) } if (response >= 400) { - abort_connection(conn, S_FTP_UNAVAIL); + abort_connection(conn, connection_state(S_FTP_UNAVAIL)); return; } - ftp_send_retr_req(conn, S_GETH); + ftp_send_retr_req(conn, connection_state(S_GETH)); } /* Construct PORT command. */ @@ -673,7 +675,7 @@ add_file_cmd_to_str(struct connection *conn) if (!conn->uri->data) { INTERNAL("conn->uri->data empty"); - abort_connection(conn, S_INTERNAL); + abort_connection(conn, connection_state(S_INTERNAL)); goto ret; } @@ -684,7 +686,7 @@ add_file_cmd_to_str(struct connection *conn) * risky. */ ftp = mem_calloc(1, sizeof(*ftp)); if (!ftp) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); goto ret; } @@ -693,24 +695,24 @@ add_file_cmd_to_str(struct connection *conn) if (!init_string(&command) || !init_string(&ftp_data_command) || !init_string(&pathname)) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); goto ret; } if (!get_ftp_data_socket(conn, &ftp_data_command)) { INTERNAL("Ftp data socket failure"); - abort_connection(conn, S_INTERNAL); + abort_connection(conn, connection_state(S_INTERNAL)); goto ret; } if (!add_uri_to_string(&pathname, conn->uri, URI_PATH)) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); goto ret; } decode_uri_string(&pathname); if (!is_ftp_pathname_safe(&pathname)) { - abort_connection(conn, S_BAD_URL); + abort_connection(conn, connection_state(S_BAD_URL)); goto ret; } @@ -732,7 +734,7 @@ add_file_cmd_to_str(struct connection *conn) || !add_to_string(&command, "LIST") || !add_crlf_to_string(&command)) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); goto ret; } @@ -748,7 +750,7 @@ add_file_cmd_to_str(struct connection *conn) || !add_crlf_to_string(&command) || !add_string_to_string(&command, &ftp_data_command)) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); goto ret; } @@ -760,7 +762,7 @@ add_file_cmd_to_str(struct connection *conn) if (!add_to_string(&command, "REST ") || !add_long_to_string(&command, offset) || !add_crlf_to_string(&command)) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); goto ret; } @@ -771,7 +773,7 @@ add_file_cmd_to_str(struct connection *conn) if (!add_to_string(&command, "RETR ") || !add_string_to_string(&command, &pathname) || !add_crlf_to_string(&command)) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); goto ret; } } @@ -781,7 +783,7 @@ add_file_cmd_to_str(struct connection *conn) /* 1 byte is already reserved for cmd_buffer in struct ftp_connection_info. */ ftp = mem_realloc(ftp, sizeof(*ftp) + command.length); if (!ftp) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); goto ret; } conn->info = ftp; /* in case mem_realloc moved the buffer */ @@ -816,12 +818,12 @@ send_it_line_by_line(struct connection *conn, struct string *cmd) /* Send commands to retrieve file or directory. */ static void -ftp_send_retr_req(struct connection *conn, int state) +ftp_send_retr_req(struct connection *conn, struct connection_state state) { struct string cmd; if (!init_string(&cmd)) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } @@ -916,13 +918,13 @@ ftp_data_connect(struct connection *conn, int pf, struct sockaddr_storage *sa, if (conn->data_socket->fd != -1) { /* The server maliciously sent multiple 227 or 229 * responses. Do not leak the previous data_socket. */ - abort_connection(conn, S_FTP_ERROR); + abort_connection(conn, connection_state(S_FTP_ERROR)); return -1; } fd = socket(pf, SOCK_STREAM, 0); if (fd < 0 || set_nonblocking_fd(fd) < 0) { - abort_connection(conn, S_FTP_ERROR); + abort_connection(conn, connection_state(S_FTP_ERROR)); return -1; } @@ -947,12 +949,14 @@ ftp_retr_file(struct socket *socket, struct read_buffer *rb) response = get_ftp_response(conn, rb, 0, &sa); if (response == -1) { - abort_connection(conn, S_FTP_ERROR); + abort_connection(conn, connection_state(S_FTP_ERROR)); return; } if (!response) { - read_from_socket(conn->socket, rb, S_GETH, ftp_retr_file); + read_from_socket(conn->socket, rb, + connection_state(S_GETH), + ftp_retr_file); return; } @@ -977,7 +981,8 @@ ftp_retr_file(struct socket *socket, struct read_buffer *rb) case 2: /* PORT */ if (response >= 400) { - abort_connection(conn, S_FTP_PORT); + abort_connection(conn, + connection_state(S_FTP_PORT)); return; } break; @@ -986,7 +991,7 @@ ftp_retr_file(struct socket *socket, struct read_buffer *rb) if (response >= 400) { if (ftp->dir) { abort_connection(conn, - S_FTP_NO_FILE); + connection_state(S_FTP_NO_FILE)); return; } conn->from = 0; @@ -1010,19 +1015,20 @@ ftp_retr_file(struct socket *socket, struct read_buffer *rb) INTERNAL("WHAT???"); } - ftp_send_retr_req(conn, S_GETH); + ftp_send_retr_req(conn, connection_state(S_GETH)); return; } response = get_ftp_response(conn, rb, 2, NULL); if (response == -1) { - abort_connection(conn, S_FTP_ERROR); + abort_connection(conn, connection_state(S_FTP_ERROR)); return; } if (!response) { - read_from_socket(conn->socket, rb, S_GETH, ftp_retr_file); + read_from_socket(conn->socket, rb, connection_state(S_GETH), + ftp_retr_file); return; } @@ -1057,7 +1063,7 @@ ftp_retr_file(struct socket *socket, struct read_buffer *rb) * get_ftp_data_socket would have created the * data_socket without waiting for anything from the * server. */ - abort_connection(conn, S_FTP_ERROR); + abort_connection(conn, connection_state(S_FTP_ERROR)); return; } set_handlers(conn->data_socket->fd, (select_handler_T) ftp_data_accept, @@ -1075,13 +1081,13 @@ ftp_got_final_response(struct socket *socket, struct read_buffer *rb) int response = get_ftp_response(conn, rb, 0, NULL); if (response == -1) { - abort_connection(conn, S_FTP_ERROR); + abort_connection(conn, connection_state(S_FTP_ERROR)); return; } if (!response) { - enum connection_state state = conn->state != S_TRANS - ? S_GETH : conn->state; + struct connection_state state = !is_in_state(conn->state, S_TRANS) + ? connection_state(S_GETH) : conn->state; read_from_socket(conn->socket, rb, state, ftp_got_final_response); return; @@ -1096,25 +1102,25 @@ ftp_got_final_response(struct socket *socket, struct read_buffer *rb) if (!conn->cached || !redirect_cache(conn->cached, "/", 1, 0)) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); return; } if (response >= 400) { - abort_connection(conn, S_FTP_FILE_ERROR); + abort_connection(conn, connection_state(S_FTP_FILE_ERROR)); return; } if (ftp->conn_state == 2) { - ftp_end_request(conn, S_OK); + ftp_end_request(conn, connection_state(S_OK)); } else { ftp->conn_state = 1; - if (conn->state != S_TRANS) - set_connection_state(conn, S_GETH); + if (!is_in_state(conn->state, S_TRANS)) + set_connection_state(conn, connection_state(S_GETH)); } } @@ -1359,7 +1365,7 @@ ftp_data_accept(struct connection *conn) } else { newsock = accept(conn->data_socket->fd, NULL, NULL); if (newsock < 0) { - retry_connection(conn, -errno); + retry_connection(conn, connection_state_for_errno(errno)); return; } close(conn->data_socket->fd); @@ -1395,7 +1401,7 @@ got_something_from_data_connection(struct connection *conn) if (!conn->cached) conn->cached = get_cache_entry(conn->uri); if (!conn->cached) { out_of_mem: - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } @@ -1412,15 +1418,15 @@ out_of_mem: if (ftp->dir && !conn->from) { struct string string; - enum connection_state state; + struct connection_state state; if (!conn->uri->data) { - abort_connection(conn, S_FTP_ERROR); + abort_connection(conn, connection_state(S_FTP_ERROR)); return; } state = init_directory_listing(&string, conn->uri); - if (state != S_OK) { + if (!is_in_state(state, S_OK)) { abort_connection(conn, state); return; } @@ -1443,7 +1449,7 @@ out_of_mem: len = safe_read(conn->data_socket->fd, ftp->ftp_buffer + ftp->buf_pos, FTP_BUF_SIZE - ftp->buf_pos); if (len < 0) { - retry_connection(conn, -errno); + retry_connection(conn, connection_state_for_errno(errno)); return; } @@ -1475,7 +1481,7 @@ out_of_mem: } - set_connection_state(conn, S_TRANS); + set_connection_state(conn, connection_state(S_TRANS)); return; } @@ -1493,17 +1499,17 @@ out_of_mem: close_socket(conn->data_socket); if (ftp->conn_state == 1) { - ftp_end_request(conn, S_OK); + ftp_end_request(conn, connection_state(S_OK)); } else { ftp->conn_state = 2; - set_connection_state(conn, S_TRANS); + set_connection_state(conn, connection_state(S_TRANS)); } } static void -ftp_end_request(struct connection *conn, enum connection_state state) +ftp_end_request(struct connection *conn, struct connection_state state) { - if (state == S_OK && conn->cached) { + if (is_in_state(state, S_OK) && conn->cached) { normalize_cache_entry(conn->cached, conn->from); } diff --git a/src/protocol/gopher/gopher.c b/src/protocol/gopher/gopher.c index 6df9968a0..7fb8f8edd 100644 --- a/src/protocol/gopher/gopher.c +++ b/src/protocol/gopher/gopher.c @@ -197,9 +197,9 @@ add_uri_decoded(struct string *command, unsigned char *string, int length, command->length = strlen(command->source); } -static enum connection_state init_gopher_index_cache_entry(struct connection *conn); +static struct connection_state init_gopher_index_cache_entry(struct connection *conn); -static enum connection_state +static struct connection_state add_gopher_command(struct connection *conn, struct string *command, enum gopher_entity entity, unsigned char *selector, int selectorlen) @@ -269,11 +269,11 @@ add_gopher_command(struct connection *conn, struct string *command, return S_CONN; } -static enum connection_state +static struct connection_state init_gopher_connection_info(struct connection *conn) { struct gopher_connection_info *gopher; - enum connection_state state; + struct connection_state state; struct string command; enum gopher_entity entity = DEFAULT_GOPHER_ENTITY; unsigned char *selector = conn->uri->data; @@ -569,15 +569,15 @@ check_gopher_last_line(unsigned char *line, unsigned char *end) } /* Parse a Gopher Menu document */ -static enum connection_state +static struct connection_state read_gopher_directory_data(struct connection *conn, struct read_buffer *rb) { - enum connection_state state = S_TRANS; + struct connection_state state = connection_state(S_TRANS); struct string buffer; unsigned char *end; if (conn->from == 0) { - enum connection_state state; + struct connection_state state; state = init_directory_listing(&buffer, conn->uri); if (state != S_OK) @@ -638,7 +638,7 @@ init_gopher_cache_entry(struct connection *conn) } /* Display a Gopher Index document. */ -static enum connection_state +static struct connection_state init_gopher_index_cache_entry(struct connection *conn) { unsigned char *where; @@ -688,7 +688,7 @@ read_gopher_response_data(struct socket *socket, struct read_buffer *rb) { struct connection *conn = socket->conn; struct gopher_connection_info *gopher = conn->info; - enum connection_state state = S_TRANS; + struct connection_state state = S_TRANS; assert(gopher && gopher->entity); @@ -767,7 +767,7 @@ void gopher_protocol_handler(struct connection *conn) { struct uri *uri = conn->uri; - enum connection_state state = S_CONN; + struct connection_state state = S_CONN; switch (get_uri_port(uri)) { case 105: diff --git a/src/protocol/http/http.c b/src/protocol/http/http.c index 10ab31da2..544b3a939 100644 --- a/src/protocol/http/http.c +++ b/src/protocol/http/http.c @@ -469,7 +469,7 @@ check_http_server_bugs(struct uri *uri, struct http_connection_info *http, } static void -http_end_request(struct connection *conn, enum connection_state state, +http_end_request(struct connection *conn, struct connection_state state, int notrunc) { shutdown_connection_stream(conn); @@ -478,7 +478,7 @@ http_end_request(struct connection *conn, enum connection_state state, && (!conn->socket->ssl) /* We won't keep alive ssl connections */ && (!get_opt_bool("protocol.http.bugs.post_no_keepalive") || !conn->uri->post)) { - if (state == S_OK && conn->cached) + if (is_in_state(state, S_OK) && conn->cached) normalize_cache_entry(conn->cached, !notrunc ? conn->from : -1); set_connection_state(conn, state); add_keepalive_connection(conn, HTTP_KEEPALIVE_TIMEOUT, NULL); @@ -520,7 +520,7 @@ init_http_connection_info(struct connection *conn, int major, int minor, int clo http = mem_calloc(1, sizeof(*http)); if (!http) { - http_end_request(conn, S_OUT_OF_MEM, 0); + http_end_request(conn, connection_state(S_OUT_OF_MEM), 0); return NULL; } @@ -587,7 +587,7 @@ http_send_header(struct socket *socket) /* Sanity check for a host */ if (!uri || !uri->host || !*uri->host || !uri->hostlen) { - http_end_request(conn, S_BAD_URL, 0); + http_end_request(conn, connection_state(S_BAD_URL), 0); return; } @@ -595,7 +595,7 @@ http_send_header(struct socket *socket) if (!http) return; if (!init_string(&header)) { - http_end_request(conn, S_OUT_OF_MEM, 0); + http_end_request(conn, connection_state(S_OUT_OF_MEM), 0); return; } @@ -980,7 +980,8 @@ http_send_header(struct socket *socket) #undef POST_BUFFER_SIZE } - request_from_socket(socket, header.source, header.length, S_SENT, + request_from_socket(socket, header.source, header.length, + connection_state(S_SENT), SOCKET_END_ONCLOSE, http_got_header); done_string(&header); } @@ -1130,7 +1131,8 @@ static void read_more_http_data(struct connection *conn, struct read_buffer *rb, int already_got_anything) { - enum connection_state state = already_got_anything ? S_TRANS : conn->state; + struct connection_state state = already_got_anything + ? connection_state(S_TRANS) : conn->state; read_from_socket(conn->socket, rb, state, read_http_data); } @@ -1155,7 +1157,7 @@ read_http_data_done(struct connection *conn) } } - http_end_request(conn, S_OK, 0); + http_end_request(conn, connection_state(S_OK), 0); } /* Returns: @@ -1347,7 +1349,7 @@ read_http_data(struct socket *socket, struct read_buffer *rb) break; default: assertm(ret == -1, "Unexpected return value: %d", ret); - abort_connection(conn, S_HTTP_ERROR); + abort_connection(conn, connection_state(S_HTTP_ERROR)); } } @@ -1454,7 +1456,9 @@ http_got_header(struct socket *socket, struct read_buffer *rb) unsigned char *d; struct uri *uri = conn->proxied_uri; /* Set to the real uri */ struct http_version version = { 0, 9 }; - enum connection_state state = (conn->state != S_PROC ? S_GETH : S_PROC); + struct connection_state state = (!is_in_state(conn->state, S_PROC) + ? connection_state(S_GETH) + : connection_state(S_PROC)); int a, h = 200; int cf; @@ -1467,7 +1471,7 @@ http_got_header(struct socket *socket, struct read_buffer *rb) conn->tries = -1; } } - retry_connection(conn, S_CANT_READ); + retry_connection(conn, connection_state(S_CANT_READ)); return; } socket->state = SOCKET_RETRY_ONCLOSE; @@ -1475,7 +1479,7 @@ http_got_header(struct socket *socket, struct read_buffer *rb) again: a = get_header(rb); if (a == -1) { - abort_connection(conn, S_HTTP_ERROR); + abort_connection(conn, connection_state(S_HTTP_ERROR)); return; } if (!a) { @@ -1488,7 +1492,7 @@ again: if (a == -2) a = 0; if ((a && get_http_code(rb, &h, &version)) || h == 101) { - abort_connection(conn, S_HTTP_ERROR); + abort_connection(conn, connection_state(S_HTTP_ERROR)); return; } @@ -1501,13 +1505,13 @@ again: head = (a ? memacpy(rb->data, a) : stracpy("\r\nContent-Type: text/html\r\n")); if (!head) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } if (check_http_server_bugs(uri, http, head)) { mem_free(head); - retry_connection(conn, S_RESTART); + retry_connection(conn, connection_state(S_RESTART)); return; } @@ -1526,7 +1530,7 @@ again: if (h2 >= 100 && h2 < 600) h = h2; if (h == 101) { mem_free(head); - abort_connection(conn, S_HTTP_ERROR); + abort_connection(conn, connection_state(S_HTTP_ERROR)); return; } } @@ -1544,23 +1548,23 @@ again: if (h == 100) { mem_free(head); - state = S_PROC; + state = connection_state(S_PROC); kill_buffer_data(rb, a); goto again; } if (h < 200) { mem_free(head); - abort_connection(conn, S_HTTP_ERROR); + abort_connection(conn, connection_state(S_HTTP_ERROR)); return; } if (h == 304) { mem_free(head); - http_end_request(conn, S_OK, 1); + http_end_request(conn, connection_state(S_OK), 1); return; } if (h == 204) { mem_free(head); - http_end_request(conn, S_HTTP_204, 0); + http_end_request(conn, connection_state(S_HTTP_204), 0); return; } if (h == 200 && connection_is_https_proxy(conn) && !conn->socket->ssl) { @@ -1569,7 +1573,7 @@ again: socket->need_ssl = 1; complete_connect_socket(socket, uri, http_send_header); #else - abort_connection(conn, S_SSL_ERROR); + abort_connection(conn, connection_state(S_SSL_ERROR)); #endif return; } @@ -1577,7 +1581,7 @@ again: conn->cached = get_cache_entry(conn->uri); if (!conn->cached) { mem_free(head); - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } conn->cached->cgi = conn->cgi; @@ -1671,7 +1675,7 @@ again: if (h == 401) { if (check_http_authentication(conn, uri, conn->cached->head, "WWW-Authenticate")) { - retry_connection(conn, S_RESTART); + retry_connection(conn, connection_state(S_RESTART)); return; } @@ -1744,7 +1748,7 @@ again: if ((conn->progress->start <= 0 && conn->from > cf) || conn->from < 0) { /* We don't want this if conn->progress.start because then conn->from will * be probably value of conn->progress.start, while cf is 0. */ - abort_connection(conn, S_HTTP_ERROR); + abort_connection(conn, connection_state(S_HTTP_ERROR)); return; } @@ -1811,7 +1815,7 @@ again: if (conn->from) { conn->from = 0; mem_free(d); - retry_connection(conn, S_MODIFIED); + retry_connection(conn, connection_state(S_MODIFIED)); return; } } @@ -1843,7 +1847,7 @@ again: if (conn->from) { conn->from = 0; mem_free(d); - retry_connection(conn, S_MODIFIED); + retry_connection(conn, connection_state(S_MODIFIED)); return; } } diff --git a/src/protocol/nntp/connection.c b/src/protocol/nntp/connection.c index e054fcfd0..55853c498 100644 --- a/src/protocol/nntp/connection.c +++ b/src/protocol/nntp/connection.c @@ -105,7 +105,7 @@ init_nntp_connection_info(struct connection *conn) nntp = mem_calloc(1, sizeof(*nntp)); if (!nntp) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return NULL; } @@ -143,7 +143,7 @@ init_nntp_connection_info(struct connection *conn) break; /* FIXME: Special S_NNTP_BAD_RANGE */ - abort_connection(conn, S_BAD_URL); + abort_connection(conn, connection_state(S_BAD_URL)); return NULL; case NNTP_TARGET_ARTICLE_NUMBER: @@ -157,12 +157,12 @@ init_nntp_connection_info(struct connection *conn) /* Map nntp:/// to nntp://// so * we get only one cache entry with content. */ if (!groupend) { - enum connection_state state = S_OK; + struct connection_state state = connection_state(S_OK); conn->cached = get_cache_entry(conn->uri); if (!conn->cached || !redirect_cache(conn->cached, "/", 0, 0)) - state = S_OUT_OF_MEM; + state = connection_state(S_OUT_OF_MEM); abort_connection(conn, state); return NULL; @@ -170,7 +170,7 @@ init_nntp_connection_info(struct connection *conn) /* Reject nntp://// */ if (nntp->group.source) { - abort_connection(conn, S_BAD_URL); + abort_connection(conn, connection_state(S_BAD_URL)); return NULL; } @@ -196,7 +196,7 @@ nntp_quit(struct connection *conn) info = mem_calloc(1, sizeof(*info)); if (!info) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } @@ -208,7 +208,7 @@ nntp_quit(struct connection *conn) } static void -nntp_end_request(struct connection *conn, enum connection_state state) +nntp_end_request(struct connection *conn, struct connection_state state) { struct nntp_connection_info *nntp = conn->info; @@ -217,11 +217,11 @@ nntp_end_request(struct connection *conn, enum connection_state state) return; } - if (state == S_OK) { + if (is_in_state(state, S_OK)) { if (conn->cached) { normalize_cache_entry(conn->cached, conn->from); } - } else if (state == S_OUT_OF_MEM) { + } else if (is_in_state(state, S_OUT_OF_MEM)) { /* FIXME: Clear the socket buffers before ending so the one * grabing the keepalive connection will be able to go on. */ } @@ -239,38 +239,39 @@ read_nntp_data(struct socket *socket, struct read_buffer *rb) struct connection *conn = socket->conn; if (socket->state == SOCKET_CLOSED) { - nntp_end_request(conn, S_OK); + nntp_end_request(conn, connection_state(S_OK)); return; } - switch (read_nntp_response_data(conn, rb)) { + switch (read_nntp_response_data(conn, rb).basic) { case S_OK: nntp_send_command(conn); break; case S_OUT_OF_MEM: - nntp_end_request(conn, S_OUT_OF_MEM); + nntp_end_request(conn, connection_state(S_OUT_OF_MEM)); break; case S_TRANS: default: - read_from_socket(conn->socket, rb, S_TRANS, read_nntp_data); + read_from_socket(conn->socket, rb, connection_state(S_TRANS), + read_nntp_data); } } /* Translate NNTP code to the internal connection state. */ -static enum connection_state +static struct connection_state get_nntp_connection_state(enum nntp_code code) { switch (code) { - case NNTP_CODE_400_GOODBYE: return S_NNTP_SERVER_HANG_UP; - case NNTP_CODE_411_GROUP_UNKNOWN: return S_NNTP_GROUP_UNKNOWN; - case NNTP_CODE_423_ARTICLE_NONUMBER: return S_NNTP_ARTICLE_UNKNOWN; - case NNTP_CODE_430_ARTICLE_NOID: return S_NNTP_ARTICLE_UNKNOWN; - case NNTP_CODE_436_ARTICLE_TRANSFER: return S_NNTP_TRANSFER_ERROR; - case NNTP_CODE_480_AUTH_REQUIRED: return S_NNTP_AUTH_REQUIRED; - case NNTP_CODE_502_ACCESS_DENIED: return S_NNTP_ACCESS_DENIED; - case NNTP_CODE_503_PROGRAM_FAULT: return S_NNTP_SERVER_ERROR; + case NNTP_CODE_400_GOODBYE: return connection_state(S_NNTP_SERVER_HANG_UP); + case NNTP_CODE_411_GROUP_UNKNOWN: return connection_state(S_NNTP_GROUP_UNKNOWN); + case NNTP_CODE_423_ARTICLE_NONUMBER: return connection_state(S_NNTP_ARTICLE_UNKNOWN); + case NNTP_CODE_430_ARTICLE_NOID: return connection_state(S_NNTP_ARTICLE_UNKNOWN); + case NNTP_CODE_436_ARTICLE_TRANSFER: return connection_state(S_NNTP_TRANSFER_ERROR); + case NNTP_CODE_480_AUTH_REQUIRED: return connection_state(S_NNTP_AUTH_REQUIRED); + case NNTP_CODE_502_ACCESS_DENIED: return connection_state(S_NNTP_ACCESS_DENIED); + case NNTP_CODE_503_PROGRAM_FAULT: return connection_state(S_NNTP_SERVER_ERROR); case NNTP_CODE_412_GROUP_UNSET: case NNTP_CODE_420_ARTICLE_UNSET: @@ -287,7 +288,7 @@ get_nntp_connection_state(enum nntp_code code) default: /* Notice and error codes for stuff which is either not * supported or which is not supposed to happen. */ - return S_NNTP_ERROR; + return connection_state(S_NNTP_ERROR); }; } @@ -298,7 +299,7 @@ nntp_got_response(struct socket *socket, struct read_buffer *rb) struct nntp_connection_info *nntp = conn->info; if (socket->state == SOCKET_CLOSED) { - nntp_end_request(conn, S_OK); + nntp_end_request(conn, connection_state(S_OK)); return; } @@ -306,11 +307,12 @@ nntp_got_response(struct socket *socket, struct read_buffer *rb) switch (nntp->code) { case NNTP_CODE_NONE: - read_from_socket(conn->socket, rb, S_TRANS, nntp_got_response); + read_from_socket(conn->socket, rb, connection_state(S_TRANS), + nntp_got_response); break; case NNTP_CODE_INVALID: - nntp_end_request(conn, S_NNTP_ERROR); + nntp_end_request(conn, connection_state(S_NNTP_ERROR)); break; case NNTP_CODE_200_HELLO: @@ -320,7 +322,7 @@ nntp_got_response(struct socket *socket, struct read_buffer *rb) break; case NNTP_CODE_205_GOODBYE: - nntp_end_request(conn, S_OK); + nntp_end_request(conn, connection_state(S_OK)); break; case NNTP_CODE_215_FOLLOW_GROUPS: @@ -509,19 +511,20 @@ nntp_send_command(struct connection *conn) nntp->command = get_nntp_command(nntp); if (nntp->command == NNTP_COMMAND_NONE) { - nntp_end_request(conn, S_OK); + nntp_end_request(conn, connection_state(S_OK)); return; } if (!init_string(&req)) { - nntp_end_request(conn, S_OUT_OF_MEM); + nntp_end_request(conn, connection_state(S_OUT_OF_MEM)); return; } /* FIXME: Check non empty and < NNTP_MAX_COMMAND_LENGTH */ add_nntp_command_to_string(&req, nntp); - request_from_socket(conn->socket, req.source, req.length, S_SENT, + request_from_socket(conn->socket, req.source, req.length, + connection_state(S_SENT), SOCKET_END_ONCLOSE, nntp_got_response); done_string(&req); } @@ -567,13 +570,13 @@ news_protocol_handler(struct connection *conn) if (!*server) server = getenv("NNTPSERVER"); if (!server || !*server) { - abort_connection(conn, S_NNTP_NEWS_SERVER); + abort_connection(conn, connection_state(S_NNTP_NEWS_SERVER)); return; } conn->cached = get_cache_entry(conn->uri); if (!conn->cached || !init_string(&location)) { - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } @@ -586,5 +589,5 @@ news_protocol_handler(struct connection *conn) done_string(&location); - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); } diff --git a/src/protocol/nntp/response.c b/src/protocol/nntp/response.c index d2f011967..bf461ccc4 100644 --- a/src/protocol/nntp/response.c +++ b/src/protocol/nntp/response.c @@ -89,14 +89,14 @@ get_nntp_message_header_end(unsigned char *data, int datalen) return NULL; } -static enum connection_state +static struct connection_state init_nntp_header(struct connection *conn, struct read_buffer *rb) { struct nntp_connection_info *nntp = conn->info; if (!conn->cached) { conn->cached = get_cache_entry(conn->uri); - if (!conn->cached) return S_OUT_OF_MEM; + if (!conn->cached) return connection_state(S_OUT_OF_MEM); } else if (conn->cached->head || conn->cached->content_type) { /* If the head is set wipe out the content to be sure */ @@ -107,7 +107,7 @@ init_nntp_header(struct connection *conn, struct read_buffer *rb) /* XXX: Override any Content-Type line in the header */ mem_free_set(&conn->cached->content_type, stracpy("text/html")); if (!conn->cached->content_type) - return S_OUT_OF_MEM; + return connection_state(S_OUT_OF_MEM); switch (nntp->target) { case NNTP_TARGET_ARTICLE_NUMBER: @@ -119,12 +119,12 @@ init_nntp_header(struct connection *conn, struct read_buffer *rb) end = get_nntp_message_header_end(rb->data, rb->length); if (!end) { /* Redo the whole cache entry thing next time */ - return S_TRANS; + return connection_state(S_TRANS); } /* FIXME: Add the NNTP response code line */ conn->cached->head = stracpy("FIXME NNTP response code\r\n"); - if (!conn->cached->head) return S_OUT_OF_MEM; + if (!conn->cached->head) return connection_state(S_OUT_OF_MEM); add_to_strn(&conn->cached->head, rb->data); @@ -140,7 +140,7 @@ init_nntp_header(struct connection *conn, struct read_buffer *rb) break; } - return S_OK; + return connection_state(S_OK); } @@ -462,31 +462,31 @@ add_nntp_html_line(struct string *html, struct connection *conn, add_char_to_string(html, '\n'); } -enum connection_state +struct connection_state read_nntp_response_data(struct connection *conn, struct read_buffer *rb) { struct string html; unsigned char *end; - enum connection_state state = S_TRANS; + struct connection_state state = connection_state(S_TRANS); if (conn->from == 0) { - switch (init_nntp_header(conn, rb)) { + switch (init_nntp_header(conn, rb).basic) { case S_OK: break; case S_OUT_OF_MEM: - return S_OUT_OF_MEM; + return connection_state(S_OUT_OF_MEM); case S_TRANS: - return S_TRANS; + return connection_state(S_TRANS); default: - return S_NNTP_ERROR; + return connection_state(S_NNTP_ERROR); } } if (!init_string(&html)) - return S_OUT_OF_MEM; + return connection_state(S_OUT_OF_MEM); if (conn->from == 0) add_nntp_html_start(&html, conn); @@ -495,7 +495,7 @@ read_nntp_response_data(struct connection *conn, struct read_buffer *rb) unsigned char *line = check_nntp_line(rb->data, end); if (!line) { - state = S_OK; + state = connection_state(S_OK); break; } @@ -505,7 +505,7 @@ read_nntp_response_data(struct connection *conn, struct read_buffer *rb) kill_buffer_data(rb, end - rb->data); } - if (state != S_TRANS) + if (!is_in_state(state, S_TRANS)) add_nntp_html_end(&html, conn); add_fragment(conn->cached, conn->from, html.source, html.length); diff --git a/src/protocol/nntp/response.h b/src/protocol/nntp/response.h index 818e4fd00..dd1fc09ba 100644 --- a/src/protocol/nntp/response.h +++ b/src/protocol/nntp/response.h @@ -13,7 +13,7 @@ struct read_buffer; * S_TRANS (transferring) means 'end-of-text' not reached yet * S_OK means no more text expected * S_OUT_OF_MEM allocation failure of some sort */ -enum connection_state +struct connection_state read_nntp_response_data(struct connection *conn, struct read_buffer *rb); /* Reads the first line in the NNTP response from the @rb read buffer and diff --git a/src/protocol/protocol.c b/src/protocol/protocol.c index 78921f572..333036566 100644 --- a/src/protocol/protocol.c +++ b/src/protocol/protocol.c @@ -212,7 +212,7 @@ static void generic_external_protocol_handler(struct session *ses, struct uri *uri) { /* [gettext_accelerator_context(generic_external_protocol_handler)] */ - enum connection_state state; + struct connection_state state; switch (uri->protocol) { case PROTOCOL_JAVASCRIPT: @@ -220,18 +220,18 @@ generic_external_protocol_handler(struct session *ses, struct uri *uri) ecmascript_protocol_handler(ses, uri); return; #else - state = S_NO_JAVASCRIPT; + state = connection_state(S_NO_JAVASCRIPT); #endif break; case PROTOCOL_UNKNOWN: - state = S_UNKNOWN_PROTOCOL; + state = connection_state(S_UNKNOWN_PROTOCOL); break; default: #ifndef CONFIG_SSL if (get_protocol_need_ssl(uri->protocol)) { - state = S_SSL_ERROR; + state = connection_state(S_SSL_ERROR); break; } #endif diff --git a/src/protocol/proxy.c b/src/protocol/proxy.c index ca6fdcdb4..dd6054e35 100644 --- a/src/protocol/proxy.c +++ b/src/protocol/proxy.c @@ -55,7 +55,7 @@ proxy_probe_no_proxy(unsigned char *url, unsigned char *no_proxy) static struct uri * proxy_uri(struct uri *uri, unsigned char *proxy, - enum connection_state *connection_state) + struct connection_state *error_state) { struct string string; @@ -70,10 +70,10 @@ proxy_uri(struct uri *uri, unsigned char *proxy, /* XXX: Assume the problem is due to @proxy having bad format. * This is a lot faster easier than checking the format. */ if (!uri) - *connection_state = S_PROXY_ERROR; + *error_state = connection_state(S_PROXY_ERROR); } else { uri = NULL; - *connection_state = S_OUT_OF_MEM; + *error_state = connection_state(S_OUT_OF_MEM); } done_string(&string); @@ -118,7 +118,7 @@ get_protocol_proxy(unsigned char *opt, static struct uri * get_proxy_worker(struct uri *uri, unsigned char *proxy, - enum connection_state *connection_state) + struct connection_state *error_state) { unsigned char *protocol_proxy = NULL; @@ -126,7 +126,7 @@ get_proxy_worker(struct uri *uri, unsigned char *proxy, if (*proxy) { proxy = strip_proxy_protocol(proxy, "http://", "ftp://"); - return proxy_uri(uri, proxy, connection_state); + return proxy_uri(uri, proxy, error_state); } /* "" from script_hook_get_proxy() */ @@ -177,14 +177,14 @@ get_proxy_worker(struct uri *uri, unsigned char *proxy, if (!no_proxy || !*no_proxy) no_proxy = getenv("no_proxy"); if (!proxy_probe_no_proxy(uri->host, no_proxy)) - return proxy_uri(uri, protocol_proxy, connection_state); + return proxy_uri(uri, protocol_proxy, error_state); } return get_composed_uri(uri, URI_BASE); } struct uri * -get_proxy_uri(struct uri *uri, enum connection_state *connection_state) +get_proxy_uri(struct uri *uri, struct connection_state *error_state) { if (uri->protocol == PROTOCOL_PROXY) { return get_composed_uri(uri, URI_BASE); @@ -196,11 +196,11 @@ get_proxy_uri(struct uri *uri, enum connection_state *connection_state) set_event_id(get_proxy_event_id, "get-proxy"); trigger_event(get_proxy_event_id, &tmp, struri(uri)); - uri = get_proxy_worker(uri, tmp, connection_state); + uri = get_proxy_worker(uri, tmp, error_state); mem_free_if(tmp); return uri; #else - return get_proxy_worker(uri, NULL, connection_state); + return get_proxy_worker(uri, NULL, error_state); #endif } } diff --git a/src/protocol/proxy.h b/src/protocol/proxy.h index eb193de79..bb399567d 100644 --- a/src/protocol/proxy.h +++ b/src/protocol/proxy.h @@ -1,14 +1,14 @@ #ifndef EL__PROTOCOL_PROXY_H #define EL__PROTOCOL_PROXY_H -enum connection_state; +struct connection_state; struct uri; /* Checks if the passed URI has been configured to go through a proxy. The * fragment is removed from the returned URI. */ /* If @connection_state is non-NULL it will be set to indicate what error * occurred if the function returns NULL. */ -struct uri *get_proxy_uri(struct uri *uri, enum connection_state *connection_state); +struct uri *get_proxy_uri(struct uri *uri, struct connection_state *connection_state); /* ``Translates'' the passed URI into the URI being proxied. If it is not a * proxy:// URI it will return the URI with the fragment removed. */ diff --git a/src/protocol/smb/smb2.c b/src/protocol/smb/smb2.c index 4ecd99c57..30452705e 100644 --- a/src/protocol/smb/smb2.c +++ b/src/protocol/smb/smb2.c @@ -71,10 +71,13 @@ static FILE *header_out, *data_out; * process, and it would be very cumbersome to free those. */ static void -smb_error(int error) +smb_error(struct connection_state error) { + if (is_system_error(error)) + fprintf(data_out, "S%d\n", (int) error.syserr); + else + fprintf(data_out, "I%d\n", (int) error.basic); fputs("text/x-error", header_out); - fprintf(data_out, "%d\n", error); exit(1); } @@ -252,8 +255,8 @@ smb_directory(int dir, struct uri *uri) struct string buf; unsigned char dircolor[8] = ""; - if (init_directory_listing(&buf, uri) != S_OK) { - smb_error(-S_OUT_OF_MEM); + if (!is_in_state(init_directory_listing(&buf, uri), S_OK)) { + smb_error(connection_state(S_OUT_OF_MEM)); } fputs("text/html", header_out); @@ -297,7 +300,7 @@ do_smb(struct connection *conn) unsigned char *uri_string = get_uri_string(uri, URI_HOST | URI_PORT | URI_DATA); if (!uri_string || !init_string(&string)) { - smb_error(-S_OUT_OF_MEM); + smb_error(connection_state(S_OUT_OF_MEM)); } /* Must URI-encode the username and password to avoid * ambiguity if they contain "/:@" characters. @@ -320,10 +323,10 @@ do_smb(struct connection *conn) } if (!url) { - smb_error(-S_OUT_OF_MEM); + smb_error(connection_state(S_OUT_OF_MEM)); } if (smbc_init(smb_auth, 0)) { - smb_error(errno); + smb_error(connection_state_for_errno(errno)); }; dir = smbc_opendir(url); @@ -345,12 +348,12 @@ do_smb(struct connection *conn) * for credentials. */ if (errno == ENOENT && errno_from_opendir == EACCES) errno = errno_from_opendir; - smb_error(errno); + smb_error(connection_state_for_errno(errno)); } res = smbc_fstat(file, &sb); if (res) { - smb_error(res); + smb_error(connection_state_for_errno(res)); } /* filesize */ fprintf(header_out, "%" OFF_PRINT_FORMAT, @@ -375,7 +378,7 @@ static void prompt_username_pw(struct connection *conn) { add_auth_entry(conn->uri, "Samba", NULL, NULL, 0); - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); } static void @@ -383,10 +386,10 @@ smb_got_error(struct socket *socket, struct read_buffer *rb) { int len = rb->length; struct connection *conn = socket->conn; - int error; + struct connection_state error; if (len < 0) { - abort_connection(conn, -errno); + abort_connection(conn, connection_state_for_errno(errno)); return; } @@ -396,20 +399,28 @@ smb_got_error(struct socket *socket, struct read_buffer *rb) * pipe. */ assert(rb->freespace >= 1); if_assert_failed { - abort_connection(conn, S_INTERNAL); + abort_connection(conn, connection_state(S_INTERNAL)); return; } rb->data[len] = '\0'; - error = atoi(rb->data); - kill_buffer_data(rb, len); - switch (error) { - case EACCES: - prompt_username_pw(conn); + switch (rb->data[0]) { + case 'S': + error = connection_state_for_errno(atoi(rb->data + 1)); + break; + case 'I': + error = connection_state(atoi(rb->data + 1)); break; default: - abort_connection(conn, -error); + ERROR("malformed error code: %s", rb->data); + error = connection_state(S_INTERNAL); break; } + kill_buffer_data(rb, len); + + if (is_system_error(error) && error.syserr == EACCES) + prompt_username_pw(conn); + else + abort_connection(conn, error); } static void @@ -419,12 +430,12 @@ smb_got_data(struct socket *socket, struct read_buffer *rb) struct connection *conn = socket->conn; if (len < 0) { - abort_connection(conn, -errno); + abort_connection(conn, connection_state_for_errno(errno)); return; } if (!len) { - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); return; } @@ -435,7 +446,7 @@ smb_got_data(struct socket *socket, struct read_buffer *rb) conn->from += len; kill_buffer_data(rb, len); - read_from_socket(socket, rb, S_TRANS, smb_got_data); + read_from_socket(socket, rb, connection_state(S_TRANS), smb_got_data); } static void @@ -454,7 +465,7 @@ smb_got_header(struct socket *socket, struct read_buffer *rb) * and assume abort_connection will do them?) */ close_socket(socket); close_socket(conn->data_socket); - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } socket->state = SOCKET_END_ONCLOSE; @@ -477,7 +488,7 @@ smb_got_header(struct socket *socket, struct read_buffer *rb) /* avoid error */ if (!conn->est_length) { - abort_connection(conn, S_OK); + abort_connection(conn, connection_state(S_OK)); return; } } @@ -492,14 +503,16 @@ smb_got_header(struct socket *socket, struct read_buffer *rb) if (!buf) { close_socket(socket); close_socket(conn->data_socket); - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } if (error) { mem_free_set(&conn->cached->content_type, stracpy("text/html")); - read_from_socket(conn->data_socket, buf, S_CONN, smb_got_error); + read_from_socket(conn->data_socket, buf, + connection_state(S_CONN), smb_got_error); } else { - read_from_socket(conn->data_socket, buf, S_CONN, smb_got_data); + read_from_socket(conn->data_socket, buf, + connection_state(S_CONN), smb_got_data); } } @@ -535,7 +548,7 @@ smb_protocol_handler(struct connection *conn) if (smb_pipe[1] >= 0) close(smb_pipe[1]); if (header_pipe[0] >= 0) close(header_pipe[0]); if (header_pipe[1] >= 0) close(header_pipe[1]); - abort_connection(conn, -s_errno); + abort_connection(conn, connection_state_for_errno(s_errno)); return; } conn->from = 0; @@ -550,7 +563,7 @@ smb_protocol_handler(struct connection *conn) close(smb_pipe[1]); close(header_pipe[0]); close(header_pipe[1]); - retry_connection(conn, -s_errno); + retry_connection(conn, connection_state_for_errno(s_errno)); return; } @@ -594,9 +607,10 @@ smb_protocol_handler(struct connection *conn) if (!buf2) { close_socket(conn->data_socket); close_socket(conn->socket); - abort_connection(conn, S_OUT_OF_MEM); + abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } - read_from_socket(conn->socket, buf2, S_CONN, smb_got_header); + read_from_socket(conn->socket, buf2, + connection_state(S_CONN), smb_got_header); } } diff --git a/src/protocol/test/stub.c b/src/protocol/test/stub.c index 8b66e34a1..dcf7125dc 100644 --- a/src/protocol/test/stub.c +++ b/src/protocol/test/stub.c @@ -85,7 +85,7 @@ get_user_program(struct terminal *term, unsigned char *progid, int progidlen) /* declared in "session/session.h" */ void -print_error_dialog(struct session *ses, enum connection_state state, +print_error_dialog(struct session *ses, struct connection_state state, struct uri *uri, enum connection_priority priority) { stub_called("print_error_dialog"); diff --git a/src/session/download.c b/src/session/download.c index a3622d474..e8c76b655 100644 --- a/src/session/download.c +++ b/src/session/download.c @@ -68,7 +68,7 @@ int download_is_progressing(struct download *download) { return download - && download->state == S_TRANS + && is_in_state(download->state, S_TRANS) && has_progress(download->progress); } @@ -318,9 +318,9 @@ download_data_store(struct download *download, struct file_download *file_downlo return; } - if (download->state != S_OK) { + if (!is_in_state(download->state, S_OK)) { unsigned char *url = get_uri_string(file_download->uri, URI_PUBLIC); - enum connection_state state = download->state; + struct connection_state state = download->state; abort_download_and_beep(file_download, term); @@ -397,7 +397,7 @@ download_data(struct download *download, struct file_download *file_download) done_uri(file_download->uri); file_download->uri = get_uri_reference(cached->redirect); - file_download->download.state = S_WAIT_REDIR; + file_download->download.state = connection_state(S_WAIT_REDIR); if (file_download->dlg_data) redraw_dialog(file_download->dlg_data, 1); @@ -955,7 +955,7 @@ init_type_query(struct session *ses, struct download *download, object_lock(type_query->cached); move_download(download, &type_query->download, PRI_MAIN); - download->state = S_OK; + download->state = connection_state(S_OK); add_to_list(ses->type_queries, type_query); diff --git a/src/session/download.h b/src/session/download.h index 018f1e3f4..a2b198dc4 100644 --- a/src/session/download.h +++ b/src/session/download.h @@ -34,8 +34,8 @@ struct download { void *data; struct progress *progress; - enum connection_state state; - enum connection_state prev_error; + struct connection_state state; + struct connection_state prev_error; enum connection_priority pri; }; diff --git a/src/session/session.c b/src/session/session.c index aa7fce99c..71b37b3ec 100644 --- a/src/session/session.c +++ b/src/session/session.c @@ -241,7 +241,7 @@ get_current_download(struct session *ses) else if (have_location(ses)) download = &cur_loc(ses)->download; - if (download && download->state == S_OK) { + if (download && is_in_state(download->state, S_OK)) { struct file_to_load *ftl; foreach (ftl, ses->more_files) @@ -255,7 +255,7 @@ get_current_download(struct session *ses) } void -print_error_dialog(struct session *ses, enum connection_state state, +print_error_dialog(struct session *ses, struct connection_state state, struct uri *uri, enum connection_priority priority) { struct string msg; @@ -602,7 +602,7 @@ doc_loading_callback(struct download *download, struct session *ses) start_document_refreshes(ses); - if (download->state != S_OK) { + if (!is_in_state(download->state, S_OK)) { print_error_dialog(ses, download->state, ses->doc_view->document->uri, download->pri); @@ -1116,7 +1116,8 @@ decode_session_info(struct terminal *term, struct terminal_info *info) /* End loop if initialization fails */ len = 0; } else if (bad_url) { - print_error_dialog(ses, S_BAD_URL, NULL, PRI_MAIN); + print_error_dialog(ses, connection_state(S_BAD_URL), + NULL, PRI_MAIN); } } diff --git a/src/session/session.h b/src/session/session.h index 3b18dd1db..d32c38e53 100644 --- a/src/session/session.h +++ b/src/session/session.h @@ -226,7 +226,7 @@ have_location(struct session *ses) { void set_session_referrer(struct session *ses, struct uri *referrer); void -print_error_dialog(struct session *ses, enum connection_state state, +print_error_dialog(struct session *ses, struct connection_state state, struct uri *uri, enum connection_priority priority); void process_file_requests(struct session *); diff --git a/src/session/task.c b/src/session/task.c index d9258354f..e800fec42 100644 --- a/src/session/task.c +++ b/src/session/task.c @@ -543,7 +543,8 @@ loading_callback(struct download *download, struct session *ses) if (d == DO_MOVE_DISPLAY) doc_loading_callback(download, ses); } - if (is_in_result_state(download->state) && download->state != S_OK) { + if (is_in_result_state(download->state) + && !is_in_state(download->state, S_OK)) { print_error_dialog(ses, download->state, download->conn ? download->conn->uri : NULL, download->pri); @@ -564,7 +565,7 @@ do_follow_url(struct session *ses, struct uri *uri, unsigned char *target, protocol_external_handler_T *external_handler; if (!uri) { - print_error_dialog(ses, S_BAD_URL, uri, PRI_CANCEL); + print_error_dialog(ses, connection_state(S_BAD_URL), uri, PRI_CANCEL); return; } diff --git a/src/viewer/dump/dump.c b/src/viewer/dump/dump.c index 2ea4724b2..f240129c7 100644 --- a/src/viewer/dump/dump.c +++ b/src/viewer/dump/dump.c @@ -263,7 +263,7 @@ dump_loading_callback(struct download *download, void *p) } - if (download->state != S_OK) { + if (!is_in_state(download->state, S_OK)) { usrerror(get_state_message(download->state, NULL)); program.retval = RET_ERROR; goto terminate;