LCOV - code coverage report
Current view: top level - crtools - sk-tcp.c (source / functions) Hit Total Coverage
Test: crtools.info Lines: 195 256 76.2 %
Date: 2012-12-28 Functions: 20 22 90.9 %
Branches: 83 176 47.2 %

           Branch data     Line data    Source code
       1                 :            : #include <netinet/tcp.h>
       2                 :            : #include <sys/ioctl.h>
       3                 :            : #include <linux/sockios.h>
       4                 :            : #include <unistd.h>
       5                 :            : #include <stdlib.h>
       6                 :            : #include <sys/mman.h>
       7                 :            : #include <string.h>
       8                 :            : 
       9                 :            : #include "crtools.h"
      10                 :            : #include "util.h"
      11                 :            : #include "list.h"
      12                 :            : #include "log.h"
      13                 :            : #include "types.h"
      14                 :            : #include "files.h"
      15                 :            : #include "sockets.h"
      16                 :            : #include "files.h"
      17                 :            : #include "sk-inet.h"
      18                 :            : #include "netfilter.h"
      19                 :            : #include "image.h"
      20                 :            : 
      21                 :            : #include "protobuf.h"
      22                 :            : #include "protobuf/tcp-stream.pb-c.h"
      23                 :            : 
      24                 :            : struct tcp_repair_opt {
      25                 :            :         u32     opt_code;
      26                 :            :         u32     opt_val;
      27                 :            : };
      28                 :            : 
      29                 :            : enum {
      30                 :            :         TCP_NO_QUEUE,
      31                 :            :         TCP_RECV_QUEUE,
      32                 :            :         TCP_SEND_QUEUE,
      33                 :            :         TCP_QUEUES_NR,
      34                 :            : };
      35                 :            : 
      36                 :            : #ifndef TCPOPT_SACK_PERM
      37                 :            : #define TCPOPT_SACK_PERM TCPOPT_SACK_PERMITTED
      38                 :            : #endif
      39                 :            : 
      40                 :            : static LIST_HEAD(cpt_tcp_repair_sockets);
      41                 :            : static LIST_HEAD(rst_tcp_repair_sockets);
      42                 :            : 
      43                 :         17 : static int tcp_repair_on(int fd)
      44                 :            : {
      45                 :         17 :         int ret, aux = 1;
      46                 :            : 
      47                 :         17 :         ret = setsockopt(fd, SOL_TCP, TCP_REPAIR, &aux, sizeof(aux));
      48         [ -  + ]:         17 :         if (ret < 0)
      49                 :          0 :                 pr_perror("Can't turn TCP repair mode ON");
      50                 :            : 
      51                 :         17 :         return ret;
      52                 :            : }
      53                 :            : 
      54                 :          8 : static int refresh_inet_sk(struct inet_sk_desc *sk)
      55                 :            : {
      56                 :            :         int size;
      57                 :            :         struct tcp_info info;
      58                 :            : 
      59         [ -  + ]:          8 :         if (dump_opt(sk->rfd, SOL_TCP, TCP_INFO, &info)) {
      60                 :          0 :                 pr_perror("Failt to obtain TCP_INFO");
      61                 :            :                 return -1;
      62                 :            :         }
      63                 :            : 
      64         [ -  + ]:          8 :         switch (info.tcpi_state) {
      65                 :            :         case TCP_ESTABLISHED:
      66                 :            :         case TCP_CLOSE:
      67                 :            :                 break;
      68                 :            :         default:
      69                 :          0 :                 pr_err("Unknown state %d\n", sk->state);
      70                 :            :                 return -1;
      71                 :            :         }
      72                 :            : 
      73         [ -  + ]:          8 :         if (ioctl(sk->rfd, SIOCOUTQ, &size) == -1) {
      74                 :          0 :                 pr_perror("Unable to get size of snd queue");
      75                 :            :                 return -1;
      76                 :            :         }
      77                 :            : 
      78                 :          8 :         sk->wqlen = size;
      79                 :            : 
      80         [ -  + ]:          8 :         if (ioctl(sk->rfd, SIOCINQ, &size) == -1) {
      81                 :          0 :                 pr_perror("Unable to get size of recv queue");
      82                 :            :                 return -1;
      83                 :            :         }
      84                 :            : 
      85                 :          8 :         sk->rqlen = size;
      86                 :            : 
      87                 :            :         return 0;
      88                 :            : }
      89                 :            : 
      90                 :          8 : static int tcp_repair_establised(int fd, struct inet_sk_desc *sk)
      91                 :            : {
      92                 :            :         int ret;
      93                 :            : 
      94                 :          8 :         pr_info("\tTurning repair on for socket %x\n", sk->sd.ino);
      95                 :            :         /*
      96                 :            :          * Keep the socket open in crtools till the very end. In
      97                 :            :          * case we close this fd after one task fd dumping and
      98                 :            :          * fail we'll have to turn repair mode off
      99                 :            :          */
     100                 :          8 :         sk->rfd = dup(fd);
     101         [ -  + ]:          8 :         if (sk->rfd < 0) {
     102                 :          0 :                 pr_perror("Can't save socket fd for repair");
     103                 :          0 :                 goto err1;
     104                 :            :         }
     105                 :            : 
     106         [ +  - ]:          8 :         if (!(opts.namespaces_flags & CLONE_NEWNET)) {
     107                 :          8 :                 ret = nf_lock_connection(sk);
     108         [ +  - ]:          8 :                 if (ret < 0)
     109                 :            :                         goto err2;
     110                 :            :         }
     111                 :            : 
     112                 :          8 :         ret = tcp_repair_on(sk->rfd);
     113         [ +  - ]:          8 :         if (ret < 0)
     114                 :            :                 goto err3;
     115                 :            : 
     116                 :          8 :         list_add_tail(&sk->rlist, &cpt_tcp_repair_sockets);
     117                 :            : 
     118                 :          8 :         ret = refresh_inet_sk(sk);
     119         [ -  + ]:          8 :         if (ret < 0)
     120                 :            :                 goto err1;
     121                 :            : 
     122                 :            :         return 0;
     123                 :            : 
     124                 :            : err3:
     125         [ #  # ]:          0 :         if (!(opts.namespaces_flags & CLONE_NEWNET))
     126                 :          0 :                 nf_unlock_connection(sk);
     127                 :            : err2:
     128                 :          8 :         close(sk->rfd);
     129                 :            : err1:
     130                 :            :         return -1;
     131                 :            : }
     132                 :            : 
     133                 :          0 : static void tcp_unlock_one(struct inet_sk_desc *sk)
     134                 :            : {
     135                 :            :         int ret;
     136                 :            : 
     137                 :          0 :         list_del(&sk->rlist);
     138                 :            : 
     139                 :          0 :         ret = nf_unlock_connection(sk);
     140         [ #  # ]:          0 :         if (ret < 0)
     141                 :          0 :                 pr_perror("Failed to unlock TCP connection");
     142                 :            : 
     143                 :          0 :         tcp_repair_off(sk->rfd);
     144                 :          0 :         close(sk->rfd);
     145                 :          0 : }
     146                 :            : 
     147                 :         90 : void cpt_unlock_tcp_connections(void)
     148                 :            : {
     149                 :            :         struct inet_sk_desc *sk, *n;
     150                 :            : 
     151         [ -  + ]:         90 :         list_for_each_entry_safe(sk, n, &cpt_tcp_repair_sockets, rlist)
     152                 :          0 :                 tcp_unlock_one(sk);
     153                 :         90 : }
     154                 :            : 
     155                 :            : /*
     156                 :            :  * TCP queues sequences and their relations to the code below
     157                 :            :  *
     158                 :            :  *       output queue
     159                 :            :  * net <----------------------------- sk
     160                 :            :  *        ^       ^       ^    seq >>
     161                 :            :  *        snd_una snd_nxt write_seq
     162                 :            :  *
     163                 :            :  *                     input  queue
     164                 :            :  * net -----------------------------> sk
     165                 :            :  *     << seq   ^       ^
     166                 :            :  *              rcv_nxt copied_seq
     167                 :            :  *
     168                 :            :  *
     169                 :            :  * inq_len  = rcv_nxt - copied_seq = SIOCINQ
     170                 :            :  * outq_len = write_seq - snd_una  = SIOCOUTQ
     171                 :            :  * inq_seq  = rcv_nxt
     172                 :            :  * outq_seq = write_seq
     173                 :            :  *
     174                 :            :  * On restore kernel moves the option we configure with setsockopt,
     175                 :            :  * thus we should advance them on the _len value in restore_tcp_seqs.
     176                 :            :  *
     177                 :            :  */
     178                 :            : 
     179                 :         16 : static int tcp_stream_get_queue(int sk, int queue_id,
     180                 :            :                 u32 *seq, u32 len, char **bufp)
     181                 :            : {
     182                 :            :         int ret, aux;
     183                 :            :         socklen_t auxl;
     184                 :            :         char *buf;
     185                 :            : 
     186                 :         16 :         pr_debug("\tSet repair queue %d\n", queue_id);
     187                 :         16 :         aux = queue_id;
     188                 :         16 :         auxl = sizeof(aux);
     189                 :         16 :         ret = setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &aux, auxl);
     190         [ +  - ]:         16 :         if (ret < 0)
     191                 :            :                 goto err_sopt;
     192                 :            : 
     193                 :         16 :         pr_debug("\tGet queue seq\n");
     194                 :         16 :         auxl = sizeof(*seq);
     195                 :         16 :         ret = getsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, seq, &auxl);
     196         [ +  - ]:         16 :         if (ret < 0)
     197                 :            :                 goto err_sopt;
     198                 :            : 
     199                 :         16 :         pr_info("\t`- seq %u len %u\n", *seq, len);
     200                 :            : 
     201         [ +  + ]:         16 :         if (len) {
     202                 :            :                 /*
     203                 :            :                  * Try to grab one byte more from the queue to
     204                 :            :                  * make sure there are len bytes for real
     205                 :            :                  */
     206         [ -  + ]:          5 :                 buf = xmalloc(len + 1);
     207         [ +  - ]:          5 :                 if (!buf)
     208                 :            :                         goto err_buf;
     209                 :            : 
     210                 :          5 :                 pr_debug("\tReading queue (%d bytes)\n", len);
     211                 :          5 :                 ret = recv(sk, buf, len + 1, MSG_PEEK | MSG_DONTWAIT);
     212         [ +  - ]:          5 :                 if (ret != len)
     213                 :            :                         goto err_recv;
     214                 :            :         } else
     215                 :            :                 buf = NULL;
     216                 :            : 
     217                 :         16 :         *bufp = buf;
     218                 :            :         return 0;
     219                 :            : 
     220                 :            : err_sopt:
     221                 :          0 :         pr_perror("\tsockopt failed");
     222                 :            : err_buf:
     223                 :            :         return -1;
     224                 :            : 
     225                 :            : err_recv:
     226                 :          0 :         pr_perror("\trecv failed (%d, want %d, errno %d)", ret, len, errno);
     227         [ #  # ]:         16 :         xfree(buf);
     228                 :            :         goto err_buf;
     229                 :            : }
     230                 :            : 
     231                 :          8 : static int tcp_stream_get_options(int sk, TcpStreamEntry *tse)
     232                 :            : {
     233                 :            :         int ret;
     234                 :            :         socklen_t auxl;
     235                 :            :         struct tcp_info ti;
     236                 :            : 
     237                 :          8 :         auxl = sizeof(ti);
     238                 :          8 :         ret = getsockopt(sk, SOL_TCP, TCP_INFO, &ti, &auxl);
     239         [ +  - ]:          8 :         if (ret < 0)
     240                 :            :                 goto err_sopt;
     241                 :            : 
     242                 :          8 :         auxl = sizeof(tse->mss_clamp);
     243                 :          8 :         ret = getsockopt(sk, SOL_TCP, TCP_MAXSEG, &tse->mss_clamp, &auxl);
     244         [ +  - ]:          8 :         if (ret < 0)
     245                 :            :                 goto err_sopt;
     246                 :            : 
     247                 :          8 :         tse->opt_mask = ti.tcpi_options;
     248         [ +  - ]:          8 :         if (ti.tcpi_options & TCPI_OPT_WSCALE) {
     249                 :          8 :                 tse->snd_wscale = ti.tcpi_snd_wscale;
     250                 :          8 :                 tse->rcv_wscale = ti.tcpi_rcv_wscale;
     251                 :          8 :                 tse->has_rcv_wscale = true;
     252                 :            :         }
     253                 :            : 
     254         [ +  - ]:          8 :         pr_info("\toptions: mss_clamp %x wscale %x tstamp %d sack %d\n",
     255                 :            :                         (int)tse->mss_clamp,
     256                 :            :                         ti.tcpi_options & TCPI_OPT_WSCALE ? (int)tse->snd_wscale : -1,
     257                 :            :                         ti.tcpi_options & TCPI_OPT_TIMESTAMPS ? 1 : 0,
     258                 :            :                         ti.tcpi_options & TCPI_OPT_SACK ? 1 : 0);
     259                 :            : 
     260                 :            :         return 0;
     261                 :            : 
     262                 :            : err_sopt:
     263                 :          8 :         pr_perror("\tsockopt failed");
     264                 :            :         return -1;
     265                 :            : }
     266                 :            : 
     267                 :          8 : static int dump_tcp_conn_state(struct inet_sk_desc *sk)
     268                 :            : {
     269                 :            :         int ret, img_fd;
     270                 :          8 :         TcpStreamEntry tse = TCP_STREAM_ENTRY__INIT;
     271                 :            :         char *in_buf, *out_buf;
     272                 :            : 
     273                 :            :         /*
     274                 :            :          * Read queue
     275                 :            :          */
     276                 :            : 
     277                 :          8 :         pr_info("Reading inq for socket\n");
     278                 :          8 :         tse.inq_len = sk->rqlen;
     279                 :          8 :         ret = tcp_stream_get_queue(sk->rfd, TCP_RECV_QUEUE,
     280                 :            :                         &tse.inq_seq, tse.inq_len, &in_buf);
     281         [ +  - ]:          8 :         if (ret < 0)
     282                 :            :                 goto err_in;
     283                 :            : 
     284                 :            :         /*
     285                 :            :          * Write queue
     286                 :            :          */
     287                 :            : 
     288                 :          8 :         pr_info("Reading outq for socket\n");
     289                 :          8 :         tse.outq_len = sk->wqlen;
     290                 :          8 :         ret = tcp_stream_get_queue(sk->rfd, TCP_SEND_QUEUE,
     291                 :            :                         &tse.outq_seq, tse.outq_len, &out_buf);
     292         [ +  - ]:          8 :         if (ret < 0)
     293                 :            :                 goto err_out;
     294                 :            : 
     295                 :            :         /*
     296                 :            :          * Initial options
     297                 :            :          */
     298                 :            : 
     299                 :          8 :         pr_info("Reasing options for socket\n");
     300                 :          8 :         ret = tcp_stream_get_options(sk->rfd, &tse);
     301         [ +  - ]:          8 :         if (ret < 0)
     302                 :            :                 goto err_opt;
     303                 :            : 
     304                 :            :         /*
     305                 :            :          * Push the stuff to image
     306                 :            :          */
     307                 :            : 
     308                 :          8 :         img_fd = open_image(CR_FD_TCP_STREAM, O_DUMP, sk->sd.ino);
     309         [ +  - ]:          8 :         if (img_fd < 0)
     310                 :            :                 goto err_img;
     311                 :            : 
     312                 :          8 :         ret = pb_write_one(img_fd, &tse, PB_TCP_STREAM);
     313         [ +  - ]:          8 :         if (ret < 0)
     314                 :            :                 goto err_iw;
     315                 :            : 
     316         [ +  + ]:          8 :         if (in_buf) {
     317                 :          3 :                 ret = write_img_buf(img_fd, in_buf, tse.inq_len);
     318         [ +  - ]:          3 :                 if (ret < 0)
     319                 :            :                         goto err_iw;
     320                 :            :         }
     321                 :            : 
     322         [ +  + ]:          8 :         if (out_buf) {
     323                 :          2 :                 ret = write_img_buf(img_fd, out_buf, tse.outq_len);
     324         [ +  - ]:          2 :                 if (ret < 0)
     325                 :            :                         goto err_iw;
     326                 :            :         }
     327                 :            : 
     328                 :          8 :         pr_info("Done\n");
     329                 :            : err_iw:
     330                 :          8 :         close(img_fd);
     331                 :            : err_img:
     332                 :            : err_opt:
     333         [ +  + ]:          8 :         xfree(out_buf);
     334                 :            : err_out:
     335         [ +  + ]:          8 :         xfree(in_buf);
     336                 :            : err_in:
     337                 :          8 :         return ret;
     338                 :            : }
     339                 :            : 
     340                 :         24 : int dump_one_tcp(int fd, struct inet_sk_desc *sk)
     341                 :            : {
     342         [ +  + ]:         24 :         if (sk->state != TCP_ESTABLISHED)
     343                 :            :                 return 0;
     344                 :            : 
     345                 :          8 :         pr_info("Dumping TCP connection\n");
     346                 :            : 
     347         [ +  - ]:          8 :         if (tcp_repair_establised(fd, sk))
     348                 :            :                 return -1;
     349                 :            : 
     350         [ +  - ]:          8 :         if (dump_tcp_conn_state(sk))
     351                 :            :                 return -1;
     352                 :            : 
     353                 :            :         /*
     354                 :            :          * Socket is left in repair mode, so that at the end it's just
     355                 :            :          * closed and the connection is silently terminated
     356                 :            :          */
     357                 :         24 :         return 0;
     358                 :            : }
     359                 :            : 
     360                 :         16 : static int set_tcp_queue_seq(int sk, int queue, u32 seq)
     361                 :            : {
     362                 :         16 :         pr_debug("\tSetting %d queue seq to %u\n", queue, seq);
     363                 :            : 
     364         [ -  + ]:         16 :         if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &queue, sizeof(queue)) < 0) {
     365                 :          0 :                 pr_perror("Can't set repair queue");
     366                 :          0 :                 return -1;
     367                 :            :         }
     368                 :            : 
     369         [ -  + ]:         16 :         if (setsockopt(sk, SOL_TCP, TCP_QUEUE_SEQ, &seq, sizeof(seq)) < 0) {
     370                 :          0 :                 pr_perror("Can't set queue seq");
     371                 :         16 :                 return -1;
     372                 :            :         }
     373                 :            : 
     374                 :            :         return 0;
     375                 :            : }
     376                 :            : 
     377                 :          8 : static int restore_tcp_seqs(int sk, TcpStreamEntry *tse)
     378                 :            : {
     379         [ +  - ]:          8 :         if (set_tcp_queue_seq(sk, TCP_RECV_QUEUE,
     380                 :          8 :                                 tse->inq_seq - tse->inq_len))
     381                 :            :                 return -1;
     382         [ +  - ]:          8 :         if (set_tcp_queue_seq(sk, TCP_SEND_QUEUE,
     383                 :          8 :                                 tse->outq_seq - tse->outq_len))
     384                 :            :                 return -1;
     385                 :            : 
     386                 :          8 :         return 0;
     387                 :            : }
     388                 :            : 
     389                 :          5 : static int send_tcp_queue(int sk, int queue, u32 len, int imgfd)
     390                 :            : {
     391                 :            :         int ret;
     392                 :            :         char *buf;
     393                 :            : 
     394                 :          5 :         pr_debug("\tRestoring TCP %d queue data %u bytes\n", queue, len);
     395                 :            : 
     396         [ -  + ]:          5 :         if (setsockopt(sk, SOL_TCP, TCP_REPAIR_QUEUE, &queue, sizeof(queue)) < 0) {
     397                 :          0 :                 pr_perror("Can't set repair queue");
     398                 :          0 :                 return -1;
     399                 :            :         }
     400                 :            : 
     401         [ -  + ]:          5 :         buf = xmalloc(len);
     402         [ +  - ]:          5 :         if (!buf)
     403                 :            :                 return -1;
     404                 :            : 
     405         [ +  - ]:          5 :         if (read_img_buf(imgfd, buf, len) < 0)
     406                 :            :                 return -1;
     407                 :            : 
     408                 :          5 :         ret = send(sk, buf, len, 0);
     409                 :            : 
     410         [ +  - ]:          5 :         xfree(buf);
     411                 :            : 
     412         [ -  + ]:          5 :         if (ret != len) {
     413                 :          0 :                 pr_perror("Can't restore %d queue data (%d), want %d",
     414                 :            :                                 queue, ret, len);
     415                 :          5 :                 return -1;
     416                 :            :         }
     417                 :            : 
     418                 :            :         return 0;
     419                 :            : }
     420                 :            : 
     421                 :          8 : static int restore_tcp_queues(int sk, TcpStreamEntry *tse, int fd)
     422                 :            : {
     423         [ +  - ]:          8 :         if (restore_prepare_socket(sk))
     424                 :            :                 return -1;
     425                 :            : 
     426   [ +  +  +  - ]:         11 :         if (tse->inq_len &&
     427                 :          3 :                         send_tcp_queue(sk, TCP_RECV_QUEUE, tse->inq_len, fd))
     428                 :            :                 return -1;
     429   [ +  +  +  - ]:         10 :         if (tse->outq_len &&
     430                 :          2 :                         send_tcp_queue(sk, TCP_SEND_QUEUE, tse->outq_len, fd))
     431                 :            :                 return -1;
     432                 :            : 
     433                 :            :         return 0;
     434                 :            : }
     435                 :            : 
     436                 :          8 : static int restore_tcp_opts(int sk, TcpStreamEntry *tse)
     437                 :            : {
     438                 :            :         struct tcp_repair_opt opts[4];
     439                 :          8 :         int onr = 0;
     440                 :            : 
     441                 :          8 :         pr_debug("\tRestoring TCP options\n");
     442                 :            : 
     443         [ +  - ]:          8 :         if (tse->opt_mask & TCPI_OPT_SACK) {
     444                 :          8 :                 pr_debug("\t\tWill turn SAK on\n");
     445                 :          8 :                 opts[onr].opt_code = TCPOPT_SACK_PERM;
     446                 :          8 :                 opts[onr].opt_val = 0;
     447                 :          8 :                 onr++;
     448                 :            :         }
     449                 :            : 
     450         [ +  - ]:          8 :         if (tse->opt_mask & TCPI_OPT_WSCALE) {
     451                 :          8 :                 pr_debug("\t\tWill set snd_wscale to %u\n", tse->snd_wscale);
     452                 :          8 :                 pr_debug("\t\tWill set rcv_wscale to %u\n", tse->rcv_wscale);
     453                 :          8 :                 opts[onr].opt_code = TCPOPT_WINDOW;
     454                 :          8 :                 opts[onr].opt_val = tse->snd_wscale + (tse->rcv_wscale << 16);
     455                 :          8 :                 onr++;
     456                 :            :         }
     457                 :            : 
     458         [ +  - ]:          8 :         if (tse->opt_mask & TCPI_OPT_TIMESTAMPS) {
     459                 :          8 :                 pr_debug("\t\tWill turn timestamps on\n");
     460                 :          8 :                 opts[onr].opt_code = TCPOPT_TIMESTAMP;
     461                 :          8 :                 opts[onr].opt_val = 0;
     462                 :          8 :                 onr++;
     463                 :            :         }
     464                 :            : 
     465                 :          8 :         pr_debug("Will set mss clamp to %u\n", tse->mss_clamp);
     466                 :          8 :         opts[onr].opt_code = TCPOPT_MAXSEG;
     467                 :          8 :         opts[onr].opt_val = tse->mss_clamp;
     468                 :          8 :         onr++;
     469                 :            : 
     470         [ -  + ]:          8 :         if (setsockopt(sk, SOL_TCP, TCP_REPAIR_OPTIONS,
     471                 :            :                                 opts, onr * sizeof(struct tcp_repair_opt)) < 0) {
     472                 :          8 :                 pr_perror("Can't repair options");
     473                 :            :                 return -1;
     474                 :            :         }
     475                 :            : 
     476                 :            :         return 0;
     477                 :            : }
     478                 :            : 
     479                 :          8 : static int restore_tcp_conn_state(int sk, struct inet_sk_info *ii)
     480                 :            : {
     481                 :            :         int ifd;
     482                 :            :         TcpStreamEntry *tse;
     483                 :            : 
     484                 :          8 :         pr_info("Restoring TCP connection id %x ino %x\n", ii->ie->id, ii->ie->ino);
     485                 :            : 
     486                 :          8 :         ifd = open_image_ro(CR_FD_TCP_STREAM, ii->ie->ino);
     487         [ +  - ]:          8 :         if (ifd < 0)
     488                 :            :                 goto err;
     489                 :            : 
     490         [ +  - ]:          8 :         if (pb_read_one(ifd, &tse, PB_TCP_STREAM) < 0)
     491                 :            :                 goto err_c;
     492                 :            : 
     493         [ +  - ]:          8 :         if (restore_tcp_seqs(sk, tse))
     494                 :            :                 goto err_c;
     495                 :            : 
     496         [ +  - ]:          8 :         if (inet_bind(sk, ii))
     497                 :            :                 goto err_c;
     498                 :            : 
     499         [ +  - ]:          8 :         if (inet_connect(sk, ii))
     500                 :            :                 goto err_c;
     501                 :            : 
     502         [ +  - ]:          8 :         if (restore_tcp_opts(sk, tse))
     503                 :            :                 goto err_c;
     504                 :            : 
     505         [ +  - ]:          8 :         if (restore_tcp_queues(sk, tse, ifd))
     506                 :            :                 goto err_c;
     507                 :            : 
     508                 :          8 :         tcp_stream_entry__free_unpacked(tse, NULL);
     509                 :          8 :         close(ifd);
     510                 :            :         return 0;
     511                 :            : 
     512                 :            : err_c:
     513                 :          0 :         tcp_stream_entry__free_unpacked(tse, NULL);
     514                 :          8 :         close(ifd);
     515                 :            : err:
     516                 :            :         return -1;
     517                 :            : }
     518                 :            : 
     519                 :            : /*
     520                 :            :  * rst_tcp_socks contains sockets in repair mode,
     521                 :            :  * which will be off in restorer before resuming.
     522                 :            :  */
     523                 :            : static int *rst_tcp_socks = NULL;
     524                 :            : static int rst_tcp_socks_num = 0;
     525                 :            : int rst_tcp_socks_size = 0;
     526                 :            : 
     527                 :        349 : int rst_tcp_socks_remap(void *addr)
     528                 :            : {
     529                 :            :         void *ret;
     530         [ +  + ]:        349 :         if (!rst_tcp_socks) {
     531         [ -  + ]:        343 :                 BUG_ON(rst_tcp_socks_size);
     532                 :            :                 return 0;
     533                 :            :         }
     534                 :            : 
     535                 :          6 :         rst_tcp_socks[rst_tcp_socks_num] = -1;
     536                 :            : 
     537                 :          6 :         ret = mmap(addr, rst_tcp_socks_size, PROT_READ | PROT_WRITE,
     538                 :            :                         MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0);
     539                 :            : 
     540         [ -  + ]:          6 :         if (ret != addr) {
     541                 :          0 :                 pr_perror("mmap() failed\n");
     542                 :          0 :                 return -1;
     543                 :            :         }
     544                 :            : 
     545                 :          6 :         memcpy(addr, rst_tcp_socks, rst_tcp_socks_size);
     546                 :            : 
     547                 :        349 :         return 0;
     548                 :            : }
     549                 :            : 
     550                 :          8 : static int rst_tcp_socks_add(int fd)
     551                 :            : {
     552                 :            :         /* + 2 = ( new one + guard (-1) ) */
     553         [ +  + ]:          8 :         if ((rst_tcp_socks_num + 2) * sizeof(int) > rst_tcp_socks_size) {
     554                 :          6 :                 rst_tcp_socks_size += PAGE_SIZE;
     555         [ -  + ]:          6 :                 rst_tcp_socks = xrealloc(rst_tcp_socks, rst_tcp_socks_size);
     556         [ +  - ]:          6 :                 if (rst_tcp_socks == NULL)
     557                 :            :                         return -1;
     558                 :            :         }
     559                 :            : 
     560                 :          8 :         rst_tcp_socks[rst_tcp_socks_num++] = fd;
     561                 :          8 :         return 0;
     562                 :            : }
     563                 :            : 
     564                 :          8 : int restore_one_tcp(int fd, struct inet_sk_info *ii)
     565                 :            : {
     566                 :          8 :         pr_info("Restoring TCP connection\n");
     567                 :            : 
     568         [ +  - ]:          8 :         if (tcp_repair_on(fd))
     569                 :            :                 return -1;
     570                 :            : 
     571         [ +  - ]:          8 :         if (rst_tcp_socks_add(fd))
     572                 :            :                 return -1;
     573                 :            : 
     574         [ +  - ]:          8 :         if (restore_tcp_conn_state(fd, ii))
     575                 :            :                 return -1;
     576                 :            : 
     577                 :          8 :         return 0;
     578                 :            : }
     579                 :            : 
     580                 :         16 : void tcp_locked_conn_add(struct inet_sk_info *ii)
     581                 :            : {
     582                 :         16 :         list_add_tail(&ii->rlist, &rst_tcp_repair_sockets);
     583                 :         16 : }
     584                 :            : 
     585                 :         90 : void rst_unlock_tcp_connections(void)
     586                 :            : {
     587                 :            :         struct inet_sk_info *ii;
     588                 :            : 
     589         [ +  + ]:         98 :         list_for_each_entry(ii, &rst_tcp_repair_sockets, rlist)
     590                 :          8 :                 nf_unlock_connection_info(ii);
     591                 :         90 : }
     592                 :            : 
     593                 :          0 : void show_tcp_stream(int fd, struct cr_options *opt)
     594                 :            : {
     595                 :            :         TcpStreamEntry *tse;
     596                 :          0 :         pr_img_head(CR_FD_TCP_STREAM);
     597                 :            : 
     598         [ #  # ]:          0 :         if (pb_read_one_eof(fd, &tse, PB_TCP_STREAM) > 0) {
     599                 :          0 :                 pr_msg("IN:   seq %10u len %10u\n", tse->inq_seq, tse->inq_len);
     600                 :          0 :                 pr_msg("OUT:  seq %10u len %10u\n", tse->outq_seq, tse->outq_len);
     601                 :          0 :                 pr_msg("OPTS: %#x\n", (int)tse->opt_mask);
     602                 :          0 :                 pr_msg("\tmss_clamp %u\n", (int)tse->mss_clamp);
     603         [ #  # ]:          0 :                 if (tse->opt_mask & TCPI_OPT_WSCALE)
     604                 :          0 :                         pr_msg("\tsnd wscale %u\n", (int)tse->snd_wscale);
     605                 :          0 :                         pr_msg("\trcv wscale %u\n", (int)tse->rcv_wscale);
     606         [ #  # ]:          0 :                 if (tse->opt_mask & TCPI_OPT_TIMESTAMPS)
     607                 :          0 :                         pr_msg("\ttimestamps\n");
     608         [ #  # ]:          0 :                 if (tse->opt_mask & TCPI_OPT_SACK)
     609                 :          0 :                         pr_msg("\tsack\n");
     610                 :            : 
     611         [ #  # ]:          0 :                 if (opt->show_pages_content) {
     612                 :            :                         unsigned char *buf;
     613                 :            : 
     614         [ #  # ]:          0 :                         buf = xmalloc(max(tse->inq_len, tse->outq_len));
     615         [ #  # ]:          0 :                         if (!buf)
     616                 :            :                                 goto out;
     617                 :            : 
     618 [ #  # ][ #  # ]:          0 :                         if (tse->inq_len && read_img_buf(fd,
     619                 :            :                                                 buf, tse->inq_len) > 0) {
     620                 :          0 :                                 pr_msg("IN queue:\n");
     621                 :          0 :                                 print_data(0, buf, tse->inq_len);
     622                 :            :                         }
     623                 :            : 
     624 [ #  # ][ #  # ]:          0 :                         if (tse->outq_len && read_img_buf(fd,
     625                 :            :                                                 buf, tse->outq_len) > 0) {
     626                 :          0 :                                 pr_msg("OUT queue:\n");
     627                 :          0 :                                 print_data(0, buf, tse->outq_len);
     628                 :            :                         }
     629                 :            : 
     630         [ #  # ]:          0 :                         xfree(buf);
     631                 :            :                 }
     632                 :            : 
     633                 :          0 :                 tcp_stream_entry__free_unpacked(tse, NULL);
     634                 :          0 :                 tse = NULL;
     635                 :            :         }
     636                 :            : 
     637                 :            : out:
     638         [ #  # ]:          0 :         if (tse)
     639                 :          0 :                 tcp_stream_entry__free_unpacked(tse, NULL);
     640                 :          0 :         pr_img_tail(CR_FD_TCP_STREAM);
     641                 :          0 : }
     642                 :            : 
     643                 :          1 : int check_tcp_repair(void)
     644                 :            : {
     645                 :            :         int sk, ret;
     646                 :            : 
     647                 :          1 :         sk = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
     648         [ -  + ]:          1 :         if (sk < 0) {
     649                 :          0 :                 pr_perror("Can't create TCP socket :(\n");
     650                 :          0 :                 return -1;
     651                 :            :         }
     652                 :            : 
     653                 :          1 :         ret = tcp_repair_on(sk);
     654                 :          1 :         close(sk);
     655                 :            : 
     656                 :          1 :         return ret;
     657                 :         16 : }

Generated by: LCOV version 1.9