@@ -29,7 +29,7 @@ AC_PROG_MAKE_SET
AC_HEADER_DIRENT
AC_HEADER_STDC
AC_CHECK_HEADERS([arpa/inet.h fcntl.h netdb.h netinet/in.h stdint.h stdlib.h dnl
- string.h sys/socket.h syslog.h unistd.h])
+ string.h sys/socket.h syslog.h unistd.h netinet/tcp.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_INT32_T
@@ -107,5 +107,27 @@ AC_ARG_WITH([fortify],
dnl [ACTION-IF-NOT-GIVEN]
[AC_MSG_RESULT([default])])
+AC_MSG_CHECKING([whether tcp keepalive options are available])
+AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM(
+ [ #include <sys/socket.h>
+ #include <arpa/inet.h>
+ #include <netinet/tcp.h> ],
+ [
+ int n = 0;
+ setsockopt(-1, IPPROTO_TCP, TCP_KEEPIDLE, &n, sizeof(n));
+ setsockopt(-1, IPPROTO_TCP, TCP_KEEPCNT, &n, sizeof(n));
+ setsockopt(-1, IPPROTO_TCP, TCP_KEEPINTVL, &n, sizeof(n));
+ ]
+ )],
+ [
+ AC_MSG_RESULT([yes])
+ AC_DEFINE([HAVE_KEEPALIVE_OPTS], [1],
+ [Define to 1 if TCP_KEEPIDLE/TCP_KEEPCNT/TCP_KEEPINTVL
+ socket-level options are available.])
+ ],
+ [ AC_MSG_RESULT([no]) ],
+)
+
AC_CONFIG_FILES([Makefile libsrc/Makefile src/Makefile])
AC_OUTPUT
@@ -50,6 +50,34 @@ void usbip_setup_port_number(char *arg)
info("using port %d (\"%s\")", usbip_port, usbip_port_string);
}
+int usbip_to_int(const char *name, const char *val, int maxval)
+{
+ char *end;
+ long value = strtol(val, &end, 10);
+
+ if (end == val) {
+ err("%s: could not parse '%s' as a decimal integer", name, val);
+ return 0;
+ }
+
+ if (*end != '\0') {
+ err("%s: garbage at end of '%s'", name, val);
+ return 0;
+ }
+
+ if (value <= 0) {
+ err("%s: must be greater than zero, actual %s", name, val);
+ return 0;
+ }
+
+ if (value > maxval) {
+ err("%s: %s is too high, max=%d", name, val, maxval);
+ return 0;
+ }
+
+ return value;
+}
+
uint32_t usbip_net_pack_uint32_t(int pack, uint32_t num)
{
uint32_t i;
@@ -243,6 +271,63 @@ int usbip_net_set_keepalive(int sockfd)
return ret;
}
+#if HAVE_KEEPALIVE_OPTS
+
+int usbip_net_set_keepidle(int sockfd, int seconds)
+{
+ int ret;
+
+ ret = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, &seconds, sizeof(seconds));
+ if (ret < 0)
+ dbg("setsockopt: TCP_KEEPIDLE");
+
+ return ret;
+}
+
+int usbip_net_set_keepcnt(int sockfd, int cnt)
+{
+ int ret;
+
+ ret = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt));
+ if (ret < 0)
+ dbg("setsockopt: TCP_KEEPCNT");
+
+ return ret;
+}
+
+int usbip_net_set_keepintvl(int sockfd, int seconds)
+{
+ int ret;
+
+ ret = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, &seconds, sizeof(seconds));
+ if (ret < 0)
+ dbg("setsockopt: TCP_KEEPINTVL");
+
+ return ret;
+}
+
+#else
+
+int usbip_net_set_keepidle(int, int)
+{
+ dbg("setsockopt: TCP_KEEPIDLE is not supported");
+ return -1;
+}
+
+int usbip_net_set_keepcnt(int, int)
+{
+ dbg("setsockopt: TCP_KEEPCNT is not supported");
+ return -1;
+}
+
+int usbip_net_set_keepintvl(int, int)
+{
+ dbg("setsockopt: TCP_KEEPINTVL is not supported");
+ return -1;
+}
+
+#endif /* HAVE_KEEPALIVE_OPTS */
+
int usbip_net_set_v6only(int sockfd)
{
const int val = 1;
@@ -18,6 +18,17 @@ extern int usbip_port;
extern char *usbip_port_string;
void usbip_setup_port_number(char *arg);
+/**
+ * usbip_to_int - convert string to positive integer
+ * @name: name of the @val for logging
+ * @val: string to convert to integer using base 10
+ * @maxval: max allowed result value
+ *
+ * Return: positive integer on success, zero if conversion
+ * is not possible or value is out of range [1...maxval].
+ */
+int usbip_to_int(const char *name, const char *val, int maxval);
+
/* ---------------------------------------------------------------------- */
/* Common header for all the kinds of PDUs. */
struct op_common {
@@ -172,6 +183,9 @@ int usbip_net_recv_op_common(int sockfd, uint16_t *code, int *status);
int usbip_net_set_reuseaddr(int sockfd);
int usbip_net_set_nodelay(int sockfd);
int usbip_net_set_keepalive(int sockfd);
+int usbip_net_set_keepidle(int sockfd, int seconds);
+int usbip_net_set_keepcnt(int sockfd, int cnt);
+int usbip_net_set_keepintvl(int sockfd, int seconds);
int usbip_net_set_v6only(int sockfd);
int usbip_net_tcp_connect(char *hostname, char *port);
@@ -46,6 +46,10 @@
#define DEFAULT_PID_FILE "/var/run/" PROGNAME ".pid"
+static int tcp_keepidle;
+static int tcp_keepcnt;
+static int tcp_keepintvl;
+
static const char usbip_version_string[] = PACKAGE_STRING;
static const char usbipd_help_string[] =
@@ -75,6 +79,19 @@ static const char usbipd_help_string[] =
" -tPORT, --tcp-port PORT\n"
" Listen on TCP/IP port PORT.\n"
"\n"
+#if HAVE_KEEPALIVE_OPTS
+ " --tcp-keepidle SECONDS\n"
+ " Number of SECONDS a connection needs to be idle\n"
+ " before TCP begins sending out keep-alive probes.\n"
+ "\n"
+ " --tcp-keepcnt PROBES\n"
+ " Max. number of TCP keep-alive PROBES to send\n"
+ " before killing the connection.\n"
+ "\n"
+ " --tcp-keepintvl SECONDS\n"
+ " Number of SECONDS between TCP keep-alive probes.\n"
+ "\n"
+#endif
" -h, --help\n"
" Print this help.\n"
"\n"
@@ -88,6 +105,24 @@ static void usbipd_help(void)
printf("%s\n", usbipd_help_string);
}
+static void set_socket_options(int sockfd)
+{
+ /* should set TCP_NODELAY for usbip */
+ usbip_net_set_nodelay(sockfd);
+
+ if (usbip_net_set_keepalive(sockfd) < 0)
+ return;
+
+ if (tcp_keepidle)
+ usbip_net_set_keepidle(sockfd, tcp_keepidle);
+
+ if (tcp_keepcnt)
+ usbip_net_set_keepcnt(sockfd, tcp_keepcnt);
+
+ if (tcp_keepintvl)
+ usbip_net_set_keepintvl(sockfd, tcp_keepintvl);
+}
+
static int recv_request_import(int sockfd)
{
struct op_import_request req;
@@ -117,9 +152,7 @@ static int recv_request_import(int sockfd)
}
if (found) {
- /* should set TCP_NODELAY for usbip */
- usbip_net_set_nodelay(sockfd);
- usbip_net_set_keepalive(sockfd);
+ set_socket_options(sockfd);
/* export device needs a TCP/IP socket descriptor */
status = usbip_export_device(edev, sockfd);
@@ -586,15 +619,21 @@ static int do_standalone_mode(int daemonize, int ipv4, int ipv6)
int main(int argc, char *argv[])
{
+ enum { KEEPIDLE = 1, KEEPCNT, KEEPINTVL };
+
static const struct option longopts[] = {
{ "ipv4", no_argument, NULL, '4' },
{ "ipv6", no_argument, NULL, '6' },
{ "daemon", no_argument, NULL, 'D' },
- { "daemon", no_argument, NULL, 'D' },
{ "debug", no_argument, NULL, 'd' },
{ "device", no_argument, NULL, 'e' },
{ "pid", optional_argument, NULL, 'P' },
{ "tcp-port", required_argument, NULL, 't' },
+#if HAVE_KEEPALIVE_OPTS
+ { "tcp-keepidle", required_argument, NULL, KEEPIDLE },
+ { "tcp-keepcnt", required_argument, NULL, KEEPCNT },
+ { "tcp-keepintvl", required_argument, NULL, KEEPINTVL },
+#endif
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, 'v' },
{ NULL, 0, NULL, 0 }
@@ -609,6 +648,7 @@ int main(int argc, char *argv[])
int daemonize = 0;
int ipv4 = 0, ipv6 = 0;
int opt, rc = -1;
+ int longidx = 0;
pid_file = NULL;
@@ -621,7 +661,7 @@ int main(int argc, char *argv[])
cmd = cmd_standalone_mode;
driver = &host_driver;
for (;;) {
- opt = getopt_long(argc, argv, "46DdeP::t:hv", longopts, NULL);
+ opt = getopt_long(argc, argv, "46DdeP::t:hv", longopts, &longidx);
if (opt == -1)
break;
@@ -654,6 +694,15 @@ int main(int argc, char *argv[])
case 'e':
driver = &device_driver;
break;
+ case KEEPIDLE:
+ tcp_keepidle = usbip_to_int(longopts[longidx].name, optarg, UINT16_MAX);
+ break;
+ case KEEPCNT:
+ tcp_keepcnt = usbip_to_int(longopts[longidx].name, optarg, UINT16_MAX);
+ break;
+ case KEEPINTVL:
+ tcp_keepintvl = usbip_to_int(longopts[longidx].name, optarg, UINT16_MAX);
+ break;
case '?':
usbipd_help();
default:
- Add usbip daemon options "--tcp-keepidle SECS", "--tcp-keepcnt CNT", "--tcp-keepintvl SECS". A user can add these parameters if default values do not satisfy him/her. - If the option is passed, set corresponding socket option for accepted connection. For example, if "--tcp-keepidle 60" is passed, call setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, ...). - configure.ac handles presence of these socket options. If TCP_KEEPIDLE/TCP_KEEPCNT/TCP_KEEPINTVL are not available, corresponding program options will not be added. Signed-off-by: Vadym Hrynchyshyn <vadimgrn@gmail.com> --- tools/usb/usbip/configure.ac | 24 +++++++- tools/usb/usbip/src/usbip_network.c | 85 +++++++++++++++++++++++++++++ tools/usb/usbip/src/usbip_network.h | 14 +++++ tools/usb/usbip/src/usbipd.c | 59 ++++++++++++++++++-- 4 files changed, 176 insertions(+), 6 deletions(-)