-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathso_priority.c
More file actions
100 lines (87 loc) · 3.34 KB
/
so_priority.c
File metadata and controls
100 lines (87 loc) · 3.34 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
/*
Set SO_PRIORITY right after each socket() call.
Compile with: gcc -shared -ldl -fPIC so_priority.c -o so_priority.so
Usage: SO_PRIORITY_DEBUG=1 SO_PRIORITY_VALUE=6 LD_PRELOAD=/path/to/so_priority.so program arg1 arg2
(c) 2020-2026 - Xavier G.
This program is free software. It comes without any warranty, to
the extent permitted by applicable law. You can redistribute it
and/or modify it under the terms of the Do What The Fuck You Want
To Public License, Version 2, as published by Sam Hocevar. See
http://www.wtfpl.net/ for more details.
*/
#define _GNU_SOURCE /* RTLD_NEXT */
#include <dlfcn.h> /* dlsym, dlerror */
#include <errno.h> /* errno */
#include <stdio.h> /* dprintf */
#include <stdlib.h> /* atoi, getenv */
#include <string.h> /* strerror */
#include <sys/types.h> /* setsockopt */
#include <sys/socket.h> /* setsockopt */
#ifndef SOPRIORITY_SO_NAME
#define SOPRIORITY_SO_NAME "so_priority.so"
#endif
#ifndef SOPRIORITY_VALUE_EV
#define SOPRIORITY_VALUE_EV "SO_PRIORITY_VALUE"
#endif
#ifndef SOPRIORITY_DEBUG_EV
#define SOPRIORITY_DEBUG_EV "SO_PRIORITY_DEBUG"
#endif
typedef int (*socket_function_type)(int, int, int);
/* Pointer to the actual socket symbol. */
socket_function_type so_priority_socket = NULL;
/* SO_PRIORITY value to set; can be configured using the SO_PRIORITY_VALUE environment variable. */
int so_priority_value = 0;
/* Debug level; can be configured using the SO_PRIORITY_DEBUG environment variable. */
int so_priority_debug = 0;
int so_priority_known = 0;
/* Ask the linker to provide the actual "socket" symbol: */
static int so_priority_get_socket() {
char *error_string;
so_priority_socket = (socket_function_type)dlsym(RTLD_NEXT, "socket");
if (!so_priority_socket) {
error_string = dlerror();
if (error_string) {
dprintf(2, "%s: unable to find the actual socket symbol: %s\n", SOPRIORITY_SO_NAME, error_string);
}
else {
dprintf(2, "%s: unable to find the actual socket symbol\n", SOPRIORITY_SO_NAME);
}
return 0;
}
return 1;
}
/* Read the priority value from the environment. */
static void so_priority_set_options() {
char *str;
str = getenv(SOPRIORITY_VALUE_EV);
if (str) so_priority_value = atoi(str);
str = getenv(SOPRIORITY_DEBUG_EV);
if (str) so_priority_debug = atoi(str);
so_priority_known = 1;
}
/* Wrapper around the actual socket() function that sets SO_PRIORITY by calling setsockopt(). */
int socket(int domain, int type, int protocol) {
int ret, setsockopt_errno, socket_errno, sockfd;
if (!so_priority_socket && !so_priority_get_socket()) {
errno = ENOENT;
return -1;
}
/* Actually call socket(): */
sockfd = so_priority_socket(domain, type, protocol);
/* Do not call setsockopt() if socket() failed: */
if (sockfd < 0) return sockfd;
/* Time for the actual work: */
socket_errno = errno;
if (!so_priority_known) so_priority_set_options();
ret = setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &so_priority_value, sizeof(so_priority_value));
/* Ignore setsockopt() errors, except for debugging purposes. */
if (so_priority_debug) {
setsockopt_errno = errno;
dprintf(2, "%s: setsockopt(%d, SOL_SOCKET, SO_PRIORITY, %d, %zu) returned %d",
SOPRIORITY_SO_NAME, sockfd, so_priority_value, sizeof(so_priority_value), ret);
if (ret < 0) dprintf(2, "; errno is %d: %s", setsockopt_errno, strerror(setsockopt_errno));
dprintf(2, "\n");
}
errno = socket_errno;
return sockfd;
}