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 <sys/ioctl.h>
#include <linux/sockios.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/mman.h>
......@@ -29,11 +27,6 @@
#include "protobuf.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
struct tcp_repair_window {
u32 snd_wl1;
......@@ -92,48 +85,6 @@ static int tcp_repair_on(int fd)
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)
{
int ret;
......@@ -282,80 +233,10 @@ err_recv:
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)
{
struct libsoccr_sk *socr = sk->priv;
int ret, aux;
struct tcp_info ti;
struct cr_img *img;
TcpStreamEntry tse = TCP_STREAM_ENTRY__INIT;
char *in_buf, *out_buf;
......@@ -370,16 +251,40 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk)
goto err_r;
}
ret = refresh_inet_sk(sk, &ti);
if (ret < 0)
goto err_r;
tse.inq_len = data.inq_len;
tse.outq_len = data.outq_len;
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
*/
pr_info("Reading inq for socket\n");
tse.inq_len = sk->rqlen;
ret = tcp_stream_get_queue(sk->rfd, TCP_RECV_QUEUE,
&tse.inq_seq, tse.inq_len, &in_buf);
if (ret < 0)
......@@ -390,26 +295,11 @@ static int dump_tcp_conn_state(struct inet_sk_desc *sk)
*/
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,
&tse.outq_seq, tse.outq_len, &out_buf);
if (ret < 0)
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
*/
......
#include <netinet/tcp.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <linux/sockios.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, ...)
__attribute__ ((__format__ (__printf__, 2, 3)));
static unsigned int log_level = 0;
......@@ -63,6 +84,107 @@ void libsoccr_resume(struct libsoccr_sk *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
*/
......@@ -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)
{
struct tcp_info ti;
if (!data || data_size < SOCR_DATA_MIN_SIZE)
return -1;
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);
}
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