8000 Introduce timeouts on sockets by ethomson · Pull Request #6535 · libgit2/libgit2 · GitHub
[go: up one dir, main page]

Skip to content

Introduce timeouts on sockets #6535

8000
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
May 13, 2023
6 changes: 5 additions & 1 deletion ci/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ if [ -z "$SKIP_PROXY_TESTS" ]; then
fi

if [ -z "$SKIP_NTLM_TESTS" -o -z "$SKIP_ONLINE_TESTS" ]; then
curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.5.1/poxygit-0.5.1.jar >poxygit.jar
curl --location --silent --show-error https://github.com/ethomson/poxygit/releases/download/v0.6.0/poxygit-0.6.0.jar >poxygit.jar

echo "Starting HTTP server..."
HTTP_DIR=`mktemp -d ${TMPDIR}/http.XXXXXXXX`
Expand Down Expand Up @@ -271,9 +271,13 @@ if [ -z "$SKIP_ONLINE_TESTS" ]; then

export GITTEST_REMOTE_REDIRECT_INITIAL="http://localhost:9000/initial-redirect/libgit2/TestGitRepository"
export GITTEST_REMOTE_REDIRECT_SUBSEQUENT="http://localhost:9000/subsequent-redirect/libgit2/TestGitRepository"
export GITTEST_REMOTE_SPEED_SLOW="http://localhost:9000/speed-9600/test.git"
export GITTEST_REMOTE_SPEED_TIMESOUT="http://localhost:9000/speed-0.5/test.git"
run_test online
unset GITTEST_REMOTE_REDIRECT_INITIAL
unset GITTEST_REMOTE_REDIRECT_SUBSEQUENT
unset GITTEST_REMOTE_SPEED_SLOW
unset GITTEST_REMOTE_SPEED_TIMESOUT

# Run the online tests that immutably change global state separately
# to avoid polluting the test environment.
Expand Down
27 changes: 26 additions & 1 deletion include/git2/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,11 @@ typedef enum {
GIT_OPT_GET_OWNER_VALIDATION,
GIT_OPT_SET_OWNER_VALIDATION,
GIT_OPT_GET_HOMEDIR,
GIT_OPT_SET_HOMEDIR
GIT_OPT_SET_HOMEDIR,
GIT_OPT_SET_SERVER_CONNECT_TIMEOUT,
GIT_OPT_GET_SERVER_CONNECT_TIMEOUT,
GIT_OPT_SET_SERVER_TIMEOUT,
GIT_OPT_GET_SERVER_TIMEOUT
} git_libgit2_opt_t;

/**
Expand Down Expand Up @@ -480,6 +484,27 @@ typedef enum {
* >
* > - `path` directory of home directory.
*
* opts(GIT_OPT_GET_SERVER_CONNECT_TIMEOUT, int *timeout)
* > Gets the timeout (in milliseconds) to attempt connections to
* > a remote server.
*
* opts(GIT_OPT_SET_SERVER_CONNECT_TIMEOUT, int timeout)
* > Sets the timeout (in milliseconds) to attempt connections to
* > a remote server. This is supported only for HTTP(S) connections
* > and is not supported by SSH. Set to 0 to use the system default.
* > Note that this may not be able to be configured longer than the
* > system default, typically 75 seconds.
*
* opts(GIT_OPT_GET_SERVER_TIMEOUT, int *timeout)
* > Gets the timeout (in milliseconds) for reading from and writing
* > to a remote server.
*
* opts(GIT_OPT_SET_SERVER_TIMEOUT, int timeout)
* > Sets the timeout (in milliseconds) for reading from and writing
* > to a remote server. This is supported only for HTTP(S)
* > connections and is not supported by SSH. Set to 0 to use the
* > system default.
*
* @param option Option key
* @param ... value to set the option
* @return 0 on success, <0 on failure
Expand Down
3 changes: 2 additions & 1 deletion include/git2/errors.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,8 @@ typedef enum {
GIT_EMISMATCH = -33, /**< Hashsum mismatch in object */
GIT_EINDEXDIRTY = -34, /**< Unsaved changes in the index would be overwritten */
GIT_EAPPLYFAIL = -35, /**< Patch application failed */
GIT_EOWNER = -36 /**< The object is not owned by the current user */
GIT_EOWNER = -36, /**< The object is not owned by the current user */
GIT_TIMEOUT = -37 /**< The operation timed out */
} git_error_code;

/**
Expand Down
18 changes: 16 additions & 2 deletions include/git2/sys/stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,22 @@ GIT_BEGIN_DECL
typedef struct git_stream {
int version;

int encrypted;
int proxy_support;
int encrypted : 1,
proxy_support : 1;

/**
* Timeout for read and write operations; can be set to `0` to
* block indefinitely.
*/
int timeout;

/**
* Timeout to connect to the remote server; can be set to `0`
* to use the system defaults. This can be shorter than the
* system default - often 75 seconds - but cannot be longer.
*/
int connect_timeout;

int GIT_CALLBACK(connect)(struct git_stream *);
int GIT_CALLBACK(certificate)(git_cert **, struct git_stream *);
int GIT_CALLBACK(set_proxy)(struct git_stream *, const git_proxy_options *proxy_opts);
Expand Down
13 changes: 11 additions & 2 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,17 @@ check_prototype_definition_safe(qsort_s

# random / entropy data

check_function_exists(getentropy GIT_RAND_GETENTROPY)
check_function_exists(getloadavg GIT_RAND_GETLOADAVG)
check_symbol_exists(getentropy unistd.h GIT_RAND_GETENTROPY)
check_symbol_exists(getloadavg stdlib.h GIT_RAND_GETLOADAVG)

# poll

if(WIN32)
set(GIT_IO_WSAPOLL 1)
else()
check_symbol_exists(poll poll.h GIT_IO_POLL)
check_symbol_exists(select sys/select.h GIT_IO_SELECT)
endif()

# determine architecture of the machine

Expand Down
17 changes: 9 additions & 8 deletions src/cli/progress.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
/*
* Show updates to the percentage and number of objects received
* separately from the throughput to give an accurate progress while
* avoiding too much noise on the screen.
* avoiding too much noise on the screen. (In milliseconds.)
*/
#define PROGRESS_UPDATE_TIME 0.10
#define THROUGHPUT_UPDATE_TIME 1.00
#define PROGRESS_UPDATE_TIME 60
#define THROUGHPUT_UPDATE_TIME 500

#define is_nl(c) ((c) == '\r' || (c) == '\n')

Expand Down Expand Up @@ -54,7 +54,7 @@ static int progress_write(cli_progress *progress, bool force, git_str *line)
bool has_nl;
size_t no_nl = no_nl_len(line->ptr, line->size);
size_t nl = nl_len(&has_nl, line->ptr + no_nl, line->size - no_nl);
double now = git__timer();
uint64_t now = git_time_monotonic();
size_t i;

/* Avoid spamming the console with progress updates */
Expand Down Expand Up @@ -191,20 +191,21 @@ static int fetch_receiving(
{
char *recv_units[] = { "B", "KiB", "MiB", "GiB", "TiB", NULL };
char *rate_units[] = { "B/s", "KiB/s", "MiB/s", "GiB/s", "TiB/s", NULL };
uint64_t now, elapsed;

double now, recv_len, rate, elapsed;
double recv_len, rate;
size_t recv_unit_idx = 0, rate_unit_idx = 0;
bool done = (stats->received_objects == stats->total_objects);

if (!progress->action_start)
progress->action_start = git__timer();
progress->action_start = git_time_monotonic();

if (done && progress->action_finish)
now = progress->action_finish;
else if (done)
progress->action_finish = now = git__timer();
progress->action_finish = now = git_time_monotonic();
else
now = git__timer();
now = git_time_monotonic();

if (progress->throughput_update &&
now - progress->throughput_update < THROUGHPUT_UPDATE_TIME) {
Expand Down
8 changes: 4 additions & 4 deletions src/cli/progress.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,19 +30,19 @@ typedef struct {
cli_progress_t action;

/* Actions may time themselves (eg fetch) but are not required to */
double action_start;
double action_finish;
uint64_t action_start;
uint64_t action_finish;

/* Last console update, avoid too frequent updates. */
double last_update;
uint64_t last_update;

/* Accumulators for partial output and deferred updates. */
git_str sideband;
git_str onscreen;
git_str deferred;

/* Last update about throughput */
double throughput_update;
uint64_t throughput_update;
double throughput_bytes;
} cli_progress;

Expand Down
1 change: 0 additions & 1 deletion src/libgit2/fetch.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
#include "remote.h"
#include "refspec.h"
#include "pack.h"
#include "netops.h"
#include "repository.h"
#include "refs.h"
#include "transports/smart.h"
Expand Down
2 changes: 0 additions & 2 deletions src/libgit2/fetch.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@

#include "git2/remote.h"

#include "netops.h"

int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts);

int git_fetch_download_pack(git_remote *remote);
Expand Down
36 changes: 36 additions & 0 deletions src/libgit2/libgit2.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ extern size_t git_indexer__max_objects;
extern bool git_disable_pack_keep_file_checks;
extern int git_odb__packed_priority;
extern int git_odb__loose_priority;
extern int git_socket_stream__connect_timeout;
extern int git_socket_stream__timeout;

char *git__user_agent;
char *git__ssl_ciphers;
Expand Down Expand Up @@ -436,6 +438,40 @@ int git_libgit2_opts(int key, ...)
error = git_sysdir_set(GIT_SYSDIR_HOME, va_arg(ap, const char *));
break;

case GIT_OPT_GET_SERVER_CONNECT_TIMEOUT:
*(va_arg(ap, int *)) = git_socket_stream__connect_timeout;
break;

case GIT_OPT_SET_SERVER_CONNECT_TIMEOUT:
{
int timeout = va_arg(ap, int);

if (timeout < 0) {
git_error_set(GIT_ERROR_INVALID, "invalid connect timeout");
error = -1;
} else {
git_socket_stream__connect_timeout = timeout;
}
}
break;

case GIT_OPT_GET_SERVER_TIMEOUT:
*(va_arg(ap, int *)) = git_socket_stream__timeout;
break;

case GIT_OPT_SET_SERVER_TIMEOUT:
{
int timeout = va_arg(ap, int);

if (timeout < 0) {
git_error_set(GIT_ERROR_INVALID, "invalid timeout");
error = -1;
} else {
git_socket_stream__timeout = timeout;
}
}
break;

default:
git_error_set(GIT_ERROR_INVALID, "invalid option key");
error = -1;
Expand Down
124 changes: 0 additions & 124 deletions src/libgit2/netops.c

This file was deleted.

Loading
0