Commit d98c0ea6 authored by Pavel Emelyanov's avatar Pavel Emelyanov

soccr/tcp: Fill actual connection info using the library

Signed-off-by: 's avatarPavel Emelyanov <xemul@virtuozzo.com>
parent 4fdc20ed
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <sys/ioctl.h>
#include <linux/sockios.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <sys/mman.h> #include <sys/mman.h>
...@@ -29,11 +27,6 @@ ...@@ -29,11 +27,6 @@
#include "protobuf.h" #include "protobuf.h"
#include "images/tcp-stream.pb-c.h" #include "images/tcp-stream.pb-c.h"
#ifndef SIOCOUTQNSD
/* MAO - Define SIOCOUTQNSD ioctl if we don't have it */
#define SIOCOUTQNSD 0x894B
#endif
#ifndef CONFIG_HAS_TCP_REPAIR_WINDOW #ifndef CONFIG_HAS_TCP_REPAIR_WINDOW
struct tcp_repair_window { struct tcp_repair_window {
u32 snd_wl1; u32 snd_wl1;
...@@ -92,48 +85,6 @@ static int tcp_repair_on(int fd) ...@@ -92,48 +85,6 @@ static int tcp_repair_on(int fd)
return ret; return ret;
} }
static int refresh_inet_sk(struct inet_sk_desc *sk, struct tcp_info *ti)
{
int size;
if (dump_opt(sk->rfd, SOL_TCP, TCP_INFO, ti)) {
pr_perror("Failed to obtain TCP_INFO");
return -1;
}
switch (ti->tcpi_state) {
case TCP_ESTABLISHED:
case TCP_CLOSE:
break;
default:
pr_err("Unknown state %d\n", sk->state);
return -1;
}
if (ioctl(sk->rfd, SIOCOUTQ, &size) == -1) {
pr_perror("Unable to get size of snd queue");
return -1;
}
sk->wqlen = size;
if (ioctl(sk->rfd, SIOCOUTQNSD, &size) == -1) {
pr_perror("Unable to get size of unsent data");
return -1;
}
sk->uwqlen = size;
if (ioctl(sk->rfd, SIOCINQ, &size) == -1) {
pr_perror("Unable to get size of recv queue");
return -1;
}
sk->rqlen = size;
return 0;
}
static int tcp_repair_establised(int fd, struct inet_sk_desc *sk) static int tcp_repair_establised(int fd, struct inet_sk_desc *sk)
{ {
int ret; int ret;
...@@ -282,80 +233,10 @@ err_recv: ...@@ -282,80 +233,10 @@ err_recv:
goto err_buf; goto err_buf;
} }
static int tcp_stream_get_options(int sk, struct tcp_info *ti, TcpStreamEntry *tse)
{
int ret;
socklen_t auxl;
int val;
auxl = sizeof(tse->mss_clamp);
ret = getsockopt(sk, SOL_TCP, TCP_MAXSEG, &tse->mss_clamp, &auxl);
if (ret < 0)
goto err_sopt;
tse->opt_mask = ti->tcpi_options;
if (ti->tcpi_options & TCPI_OPT_WSCALE) {
tse->snd_wscale = ti->tcpi_snd_wscale;
tse->rcv_wscale = ti->tcpi_rcv_wscale;
tse->has_rcv_wscale = true;
}
if (ti->tcpi_options & TCPI_OPT_TIMESTAMPS) {
auxl = sizeof(val);
ret = getsockopt(sk, SOL_TCP, TCP_TIMESTAMP, &val, &auxl);
if (ret < 0)
goto err_sopt;
tse->has_timestamp = true;
tse->timestamp = val;
}
pr_info("\toptions: mss_clamp %x wscale %x tstamp %d sack %d\n",
(int)tse->mss_clamp,
ti->tcpi_options & TCPI_OPT_WSCALE ? (int)tse->snd_wscale : -1,
ti->tcpi_options & TCPI_OPT_TIMESTAMPS ? 1 : 0,
ti->tcpi_options & TCPI_OPT_SACK ? 1 : 0);
return 0;
err_sopt:
pr_perror("\tsockopt failed");
return -1;
}
static int tcp_get_window(int sk, TcpStreamEntry *tse)
{
struct tcp_repair_window opt;
socklen_t optlen = sizeof(opt);
if (!kdat.has_tcp_window)
return 0;
if (getsockopt(sk, SOL_TCP,
TCP_REPAIR_WINDOW, &opt, &optlen)) {
pr_perror("Unable to get window properties");
return -1;
}
tse->has_snd_wl1 = true;
tse->has_snd_wnd = true;
tse->has_max_window = true;
tse->has_rcv_wnd = true;
tse->has_rcv_wup = true;
tse->snd_wl1 = opt.snd_wl1;
tse->snd_wnd = opt.snd_wnd;
tse->max_window = opt.max_window;
tse->rcv_wnd = opt.rcv_wnd;
tse->rcv_wup = opt.rcv_wup;
return 0;
}
static int dump_tcp_conn_state(struct inet_sk_desc *sk) static int dump_tcp_conn_state(struct inet_sk_desc *sk)
{ {
struct libsoccr_sk *socr = sk->priv; struct libsoccr_sk *socr = sk->priv;
int ret, aux; int ret, aux;
struct tcp_info ti;
struct cr_img *img; struct cr_img *img;
TcpStreamEntry tse = TCP_STREAM_ENTRY__INIT; TcpStreamEntry tse = TCP_STREAM_ENTRY__INIT;
char *in_buf, *out_buf; char *in_buf, *out_buf;
...@@ -370,16 +251,40 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk) ...@@ -370,16 +251,40 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk)
goto err_r; goto err_r;
} }
ret = refresh_inet_sk(sk, &ti); tse.inq_len = data.inq_len;
if (ret < 0) tse.outq_len = data.outq_len;
goto err_r; tse.unsq_len = data.unsq_len;
tse.has_unsq_len = true;
tse.mss_clamp = data.mss_clamp;
tse.opt_mask = data.opt_mask;
if (tse.opt_mask & TCPI_OPT_WSCALE) {
tse.snd_wscale = data.snd_wscale;
tse.rcv_wscale = data.rcv_wscale;
tse.has_rcv_wscale = true;
}
if (tse.opt_mask & TCPI_OPT_TIMESTAMPS) {
tse.timestamp = data.timestamp;
tse.has_timestamp = true;
}
if (data.flags & SOCCR_FLAGS_WINDOW) {
tse.has_snd_wl1 = true;
tse.has_snd_wnd = true;
tse.has_max_window = true;
tse.has_rcv_wnd = true;
tse.has_rcv_wup = true;
tse.snd_wl1 = data.snd_wl1;
tse.snd_wnd = data.snd_wnd;
tse.max_window = data.max_window;
tse.rcv_wnd = data.rcv_wnd;
tse.rcv_wup = data.rcv_wup;
}
/* /*
* Read queue * Read queue
*/ */
pr_info("Reading inq for socket\n"); pr_info("Reading inq for socket\n");
tse.inq_len = sk->rqlen;
ret = tcp_stream_get_queue(sk->rfd, TCP_RECV_QUEUE, ret = tcp_stream_get_queue(sk->rfd, TCP_RECV_QUEUE,
&tse.inq_seq, tse.inq_len, &in_buf); &tse.inq_seq, tse.inq_len, &in_buf);
if (ret < 0) if (ret < 0)
...@@ -390,26 +295,11 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk) ...@@ -390,26 +295,11 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk)
*/ */
pr_info("Reading outq for socket\n"); pr_info("Reading outq for socket\n");
tse.outq_len = sk->wqlen;
tse.unsq_len = sk->uwqlen;
tse.has_unsq_len = true;
ret = tcp_stream_get_queue(sk->rfd, TCP_SEND_QUEUE, ret = tcp_stream_get_queue(sk->rfd, TCP_SEND_QUEUE,
&tse.outq_seq, tse.outq_len, &out_buf); &tse.outq_seq, tse.outq_len, &out_buf);
if (ret < 0) if (ret < 0)
goto err_out; goto err_out;
/*
* Initial options
*/
pr_info("Reading options for socket\n");
ret = tcp_stream_get_options(sk->rfd, &ti, &tse);
if (ret < 0)
goto err_opt;
if (tcp_get_window(sk->rfd, &tse))
goto err_opt;
/* /*
* TCP socket options * TCP socket options
*/ */
......
#include <netinet/tcp.h> #include <netinet/tcp.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <linux/sockios.h>
#include "soccr.h" #include "soccr.h"
#ifndef SIOCOUTQNSD
/* MAO - Define SIOCOUTQNSD ioctl if we don't have it */
#define SIOCOUTQNSD 0x894B
#endif
#ifndef TCP_REPAIR_WINDOW
#define TCP_REPAIR_WINDOW 29
#endif
struct tcp_repair_window {
__u32 snd_wl1;
__u32 snd_wnd;
__u32 max_window;
__u32 rcv_wnd;
__u32 rcv_wup;
};
static void (*log)(unsigned int loglevel, const char *format, ...) static void (*log)(unsigned int loglevel, const char *format, ...)
__attribute__ ((__format__ (__printf__, 2, 3))); __attribute__ ((__format__ (__printf__, 2, 3)));
static unsigned int log_level = 0; static unsigned int log_level = 0;
...@@ -63,6 +84,107 @@ void libsoccr_resume(struct libsoccr_sk *sk) ...@@ -63,6 +84,107 @@ void libsoccr_resume(struct libsoccr_sk *sk)
free(sk); free(sk);
} }
static int refresh_sk(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, struct tcp_info *ti)
{
int size;
socklen_t olen = sizeof(*ti);
if (getsockopt(sk->fd, SOL_TCP, TCP_INFO, ti, &olen) || olen != sizeof(*ti)) {
loge("Failed to obtain TCP_INFO");
return -1;
}
switch (ti->tcpi_state) {
case TCP_ESTABLISHED:
case TCP_CLOSE:
break;
default:
loge("Unknown state %d\n", ti->tcpi_state);
return -1;
}
if (ioctl(sk->fd, SIOCOUTQ, &size) == -1) {
loge("Unable to get size of snd queue");
return -1;
}
data->outq_len = size;
if (ioctl(sk->fd, SIOCOUTQNSD, &size) == -1) {
loge("Unable to get size of unsent data");
return -1;
}
data->unsq_len = size;
if (ioctl(sk->fd, SIOCINQ, &size) == -1) {
loge("Unable to get size of recv queue");
return -1;
}
data->inq_len = size;
return 0;
}
static int get_stream_options(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, struct tcp_info *ti)
{
int ret;
socklen_t auxl;
int val;
auxl = sizeof(data->mss_clamp);
ret = getsockopt(sk->fd, SOL_TCP, TCP_MAXSEG, &data->mss_clamp, &auxl);
if (ret < 0)
goto err_sopt;
data->opt_mask = ti->tcpi_options;
if (ti->tcpi_options & TCPI_OPT_WSCALE) {
data->snd_wscale = ti->tcpi_snd_wscale;
data->rcv_wscale = ti->tcpi_rcv_wscale;
}
if (ti->tcpi_options & TCPI_OPT_TIMESTAMPS) {
auxl = sizeof(val);
ret = getsockopt(sk->fd, SOL_TCP, TCP_TIMESTAMP, &val, &auxl);
if (ret < 0)
goto err_sopt;
data->timestamp = val;
}
return 0;
err_sopt:
loge("\tsockopt failed");
return -1;
}
static int get_window(struct libsoccr_sk *sk, struct libsoccr_sk_data *data)
{
struct tcp_repair_window opt;
socklen_t optlen = sizeof(opt);
if (getsockopt(sk->fd, SOL_TCP,
TCP_REPAIR_WINDOW, &opt, &optlen)) {
/* Appeared since 4.8, but TCP_repair itself is since 3.11 */
if (errno == ENOPROTOOPT)
return 0;
loge("Unable to get window properties");
return -1;
}
data->flags |= SOCCR_FLAGS_WINDOW;
data->snd_wl1 = opt.snd_wl1;
data->snd_wnd = opt.snd_wnd;
data->max_window = opt.max_window;
data->rcv_wnd = opt.rcv_wnd;
data->rcv_wup = opt.rcv_wup;
return 0;
}
/* /*
* This is how much data we've had in the initial libsoccr * This is how much data we've had in the initial libsoccr
*/ */
...@@ -70,10 +192,21 @@ void libsoccr_resume(struct libsoccr_sk *sk) ...@@ -70,10 +192,21 @@ void libsoccr_resume(struct libsoccr_sk *sk)
int libsoccr_get_sk_data(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigned data_size) int libsoccr_get_sk_data(struct libsoccr_sk *sk, struct libsoccr_sk_data *data, unsigned data_size)
{ {
struct tcp_info ti;
if (!data || data_size < SOCR_DATA_MIN_SIZE) if (!data || data_size < SOCR_DATA_MIN_SIZE)
return -1; return -1;
memset(data, 0, data_size); memset(data, 0, data_size);
if (refresh_sk(sk, data, &ti))
return -2;
if (get_stream_options(sk, data, &ti))
return -3;
if (get_window(sk, data))
return -4;
return sizeof(struct libsoccr_sk_data); return sizeof(struct libsoccr_sk_data);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment