Coverage Report

Created: 2026-09-01 07:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/irssi/src/core/net-disconnect.c
Line
Count
Source
1
/*
2
 net-disconnect.c :
3
4
    Copyright (C) 1999-2000 Timo Sirainen
5
6
    This program is free software; you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation; either version 2 of the License, or
9
    (at your option) any later version.
10
11
    This program is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
16
    You should have received a copy of the GNU General Public License along
17
    with this program; if not, write to the Free Software Foundation, Inc.,
18
    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
*/
20
21
#include "module.h"
22
#include <irssi/src/core/network.h>
23
24
#include <sys/select.h>
25
26
/* when quitting, wait for max. 5 seconds before forcing to close the socket */
27
0
#define MAX_QUIT_CLOSE_WAIT 5
28
29
/* wait for max. 2 minutes for other side to close the socket */
30
0
#define MAX_CLOSE_WAIT (60*2)
31
32
typedef struct {
33
  time_t created;
34
  GIOChannel *handle;
35
  int tag;
36
} NET_DISCONNECT_REC;
37
38
static GSList *disconnects;
39
40
static int timeout_tag;
41
42
static void net_disconnect_remove(NET_DISCONNECT_REC *rec)
43
0
{
44
0
  disconnects = g_slist_remove(disconnects, rec);
45
46
0
  g_source_remove(rec->tag);
47
0
        net_disconnect(rec->handle);
48
0
  g_free(rec);
49
0
}
50
51
static void sig_disconnect(NET_DISCONNECT_REC *rec)
52
0
{
53
0
  char buf[512];
54
0
  int count, ret;
55
56
  /* check if there's any data waiting in socket. read max. 9kB so
57
     if server just keeps sending us stuff we won't get stuck */
58
0
  count = 0;
59
0
  do {
60
0
    ret = net_receive(rec->handle, buf, sizeof(buf));
61
0
    if (ret == -1) {
62
      /* socket was closed */
63
0
      net_disconnect_remove(rec);
64
0
    }
65
0
                count++;
66
0
  } while (ret == sizeof(buf) && count < 18);
67
0
}
68
69
static int sig_timeout_disconnect(void)
70
0
{
71
0
  NET_DISCONNECT_REC *rec;
72
0
  GSList *tmp, *next;
73
0
  time_t now;
74
75
  /* check if we've waited enough for sockets to close themselves */
76
0
  now = time(NULL);
77
0
  for (tmp = disconnects; tmp != NULL; tmp = next) {
78
0
    rec = tmp->data;
79
0
    next = tmp->next;
80
81
0
    if (rec->created+MAX_CLOSE_WAIT <= now)
82
0
      net_disconnect_remove(rec);
83
0
  }
84
85
0
  if (disconnects == NULL) {
86
    /* no more sockets in disconnect queue, stop calling this
87
       function */
88
0
    timeout_tag = -1;
89
0
  }
90
0
  return disconnects != NULL;
91
0
}
92
93
/* Try to let the other side close the connection, if it still isn't
94
   disconnected after certain amount of time, close it ourself */
95
void net_disconnect_later(GIOChannel *handle)
96
192
{
97
192
  NET_DISCONNECT_REC *rec;
98
99
192
  rec = g_new(NET_DISCONNECT_REC, 1);
100
192
  rec->created = time(NULL);
101
192
  rec->handle = handle;
102
192
  rec->tag = i_input_add(handle, I_INPUT_READ, (GInputFunction) sig_disconnect, rec);
103
104
192
  if (timeout_tag == -1) {
105
1
    timeout_tag = g_timeout_add(10000, (GSourceFunc)
106
1
              sig_timeout_disconnect, NULL);
107
1
  }
108
109
192
  disconnects = g_slist_append(disconnects, rec);
110
192
}
111
112
void net_disconnect_init(void)
113
8
{
114
8
  disconnects = NULL;
115
8
  timeout_tag = -1;
116
8
}
117
118
void net_disconnect_deinit(void)
119
0
{
120
0
  NET_DISCONNECT_REC *rec;
121
0
  time_t now, max;
122
0
  int first, fd;
123
0
  struct timeval tv;
124
0
  fd_set set;
125
126
  /* give the sockets a chance to disconnect themselves.. */
127
0
  max = time(NULL)+MAX_QUIT_CLOSE_WAIT;
128
0
  first = 1;
129
0
  while (disconnects != NULL) {
130
0
    rec = disconnects->data;
131
132
0
    now = time(NULL);
133
0
    if (rec->created+MAX_QUIT_CLOSE_WAIT <= now || max <= now) {
134
      /* this one has waited enough */
135
0
      net_disconnect_remove(rec);
136
0
      continue;
137
0
    }
138
139
0
                fd = g_io_channel_unix_get_fd(rec->handle);
140
0
    FD_ZERO(&set);
141
0
    FD_SET(fd, &set);
142
0
    tv.tv_sec = first ? 0 : max-now;
143
0
    tv.tv_usec = first ? 100000 : 0;
144
0
    if (select(fd+1, &set, NULL, NULL, &tv) > 0 &&
145
0
        FD_ISSET(fd, &set)) {
146
      /* data coming .. check if we can close the handle */
147
0
      sig_disconnect(rec);
148
0
    } else if (first) {
149
      /* Display the text when we have already waited
150
         for a while */
151
0
      printf("Please wait, waiting for servers to close "
152
0
             "connections..\n");
153
0
      fflush(stdout);
154
155
0
      first = 0;
156
0
    }
157
0
  }
158
0
}