NeoMutt  2022-04-29-81-g9c5a59
Teaching an old dog new tricks
DOXYGEN
socket.c
Go to the documentation of this file.
1 
31 #include "config.h"
32 #include <errno.h>
33 #include <string.h>
34 #include <time.h>
35 #include "private.h"
36 #include "mutt/lib.h"
37 #include "config/lib.h"
38 #include "core/lib.h"
39 #include "socket.h"
40 #include "connaccount.h"
41 #include "connection.h"
42 #include "protos.h"
43 #include "ssl.h"
44 
50 static int socket_preconnect(void)
51 {
52  const char *const c_preconnect = cs_subset_string(NeoMutt->sub, "preconnect");
53  if (!c_preconnect)
54  return 0;
55 
56  mutt_debug(LL_DEBUG2, "Executing preconnect: %s\n", c_preconnect);
57  const int rc = mutt_system(c_preconnect);
58  mutt_debug(LL_DEBUG2, "Preconnect result: %d\n", rc);
59  if (rc != 0)
60  {
61  const int save_errno = errno;
62  mutt_perror(_("Preconnect command failed"));
63 
64  return save_errno;
65  }
66 
67  return 0;
68 }
69 
76 int mutt_socket_open(struct Connection *conn)
77 {
78  int rc;
79 
80  if (socket_preconnect())
81  return -1;
82 
83  rc = conn->open(conn);
84 
85  mutt_debug(LL_DEBUG2, "Connected to %s:%d on fd=%d\n", conn->account.host,
86  conn->account.port, conn->fd);
87 
88  return rc;
89 }
90 
97 int mutt_socket_close(struct Connection *conn)
98 {
99  if (!conn)
100  return 0;
101 
102  int rc = -1;
103 
104  if (conn->fd < 0)
105  mutt_debug(LL_DEBUG1, "Attempt to close closed connection\n");
106  else
107  rc = conn->close(conn);
108 
109  conn->fd = -1;
110  conn->ssf = 0;
111  conn->bufpos = 0;
112  conn->available = 0;
113 
114  return rc;
115 }
116 
125 int mutt_socket_read(struct Connection *conn, char *buf, size_t len)
126 {
127  return conn->read(conn, buf, len);
128 }
129 
138 int mutt_socket_write(struct Connection *conn, const char *buf, size_t len)
139 {
140  return conn->write(conn, buf, len);
141 }
142 
152 int mutt_socket_write_d(struct Connection *conn, const char *buf, int len, int dbg)
153 {
154  int sent = 0;
155 
156  mutt_debug(dbg, "%d> %s", conn->fd, buf);
157 
158  if (conn->fd < 0)
159  {
160  mutt_debug(LL_DEBUG1, "attempt to write to closed connection\n");
161  return -1;
162  }
163 
164  while (sent < len)
165  {
166  const int rc = conn->write(conn, buf + sent, len - sent);
167  if (rc < 0)
168  {
169  mutt_debug(LL_DEBUG1, "error writing (%s), closing socket\n", strerror(errno));
170  mutt_socket_close(conn);
171 
172  return -1;
173  }
174 
175  if (rc < len - sent)
176  mutt_debug(LL_DEBUG3, "short write (%d of %d bytes)\n", rc, len - sent);
177 
178  sent += rc;
179  }
180 
181  return sent;
182 }
183 
192 int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
193 {
194  if (conn->bufpos < conn->available)
195  return conn->available - conn->bufpos;
196 
197  if (conn->poll)
198  return conn->poll(conn, wait_secs);
199 
200  return -1;
201 }
202 
210 int mutt_socket_readchar(struct Connection *conn, char *c)
211 {
212  if (conn->bufpos >= conn->available)
213  {
214  if (conn->fd >= 0)
215  conn->available = conn->read(conn, conn->inbuf, sizeof(conn->inbuf));
216  else
217  {
218  mutt_debug(LL_DEBUG1, "attempt to read from closed connection\n");
219  return -1;
220  }
221  conn->bufpos = 0;
222  if (conn->available == 0)
223  {
224  mutt_error(_("Connection to %s closed"), conn->account.host);
225  }
226  if (conn->available <= 0)
227  {
228  mutt_socket_close(conn);
229  return -1;
230  }
231  }
232  *c = conn->inbuf[conn->bufpos];
233  conn->bufpos++;
234  return 1;
235 }
236 
246 int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
247 {
248  char ch;
249  int i;
250 
251  for (i = 0; i < buflen - 1; i++)
252  {
253  if (mutt_socket_readchar(conn, &ch) != 1)
254  {
255  buf[i] = '\0';
256  return -1;
257  }
258 
259  if (ch == '\n')
260  break;
261  buf[i] = ch;
262  }
263 
264  /* strip \r from \r\n termination */
265  if (i && (buf[i - 1] == '\r'))
266  i--;
267  buf[i] = '\0';
268 
269  mutt_debug(dbg, "%d< %s\n", conn->fd, buf);
270 
271  /* number of bytes read, not strlen */
272  return i + 1;
273 }
274 
281 {
282  struct Connection *conn = mutt_mem_calloc(1, sizeof(struct Connection));
283  conn->fd = -1;
284 
285  if (type == MUTT_CONNECTION_TUNNEL)
286  {
288  }
289  else if (type == MUTT_CONNECTION_SSL)
290  {
291  int rc = mutt_ssl_socket_setup(conn);
292  if (rc < 0)
293  FREE(&conn);
294  }
295  else
296  {
297  conn->read = raw_socket_read;
298  conn->write = raw_socket_write;
299  conn->open = raw_socket_open;
300  conn->close = raw_socket_close;
301  conn->poll = raw_socket_poll;
302  }
303 
304  return conn;
305 }
306 
313 void mutt_socket_empty(struct Connection *conn)
314 {
315  if (!conn)
316  return;
317 
318  char buf[1024];
319  int bytes;
320 
321  while ((bytes = mutt_socket_poll(conn, 0)) > 0)
322  {
323  mutt_socket_read(conn, buf, MIN(bytes, sizeof(buf)));
324  }
325 }
Convenience wrapper for the config headers.
void mutt_tunnel_socket_setup(struct Connection *conn)
Sets up tunnel connection functions.
Definition: tunnel.c:233
Connection Credentials.
An open network connection (socket)
Convenience wrapper for the core headers.
int mutt_ssl_socket_setup(struct Connection *conn)
Set up SSL socket mulitplexor.
Definition: gnutls.c:1123
int raw_socket_close(struct Connection *conn)
Close a socket - Implements Connection::close() -.
Definition: raw.c:362
int raw_socket_open(struct Connection *conn)
Open a socket - Implements Connection::open() -.
Definition: raw.c:117
int raw_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block - Implements Connection::poll() -.
Definition: raw.c:324
int raw_socket_read(struct Connection *conn, char *buf, size_t len)
Read data from a socket - Implements Connection::read() -.
Definition: raw.c:264
int raw_socket_write(struct Connection *conn, const char *buf, size_t count)
Write data to a socket - Implements Connection::write() -.
Definition: raw.c:294
#define mutt_error(...)
Definition: logging.h:87
#define mutt_debug(LEVEL,...)
Definition: logging.h:84
#define mutt_perror(...)
Definition: logging.h:88
const char * cs_subset_string(const struct ConfigSubset *sub, const char *name)
Get a string config item by name.
Definition: helpers.c:317
@ LL_DEBUG3
Log at debug level 3.
Definition: logging.h:42
@ LL_DEBUG2
Log at debug level 2.
Definition: logging.h:41
@ LL_DEBUG1
Log at debug level 1.
Definition: logging.h:40
void * mutt_mem_calloc(size_t nmemb, size_t size)
Allocate zeroed memory on the heap.
Definition: memory.c:50
#define FREE(x)
Definition: memory.h:40
#define MIN(a, b)
Definition: memory.h:31
Convenience wrapper for the library headers.
#define _(a)
Definition: message.h:28
Prototypes for many functions.
int mutt_system(const char *cmd)
Run an external command.
Definition: system.c:51
GUI display the mailboxes in a side panel.
struct Connection * mutt_socket_new(enum ConnectionType type)
Allocate and initialise a new connection.
Definition: socket.c:280
int mutt_socket_close(struct Connection *conn)
Close a socket.
Definition: socket.c:97
int mutt_socket_poll(struct Connection *conn, time_t wait_secs)
Checks whether reads would block.
Definition: socket.c:192
int mutt_socket_write_d(struct Connection *conn, const char *buf, int len, int dbg)
Write data to a socket.
Definition: socket.c:152
int mutt_socket_readchar(struct Connection *conn, char *c)
Simple read buffering to speed things up.
Definition: socket.c:210
void mutt_socket_empty(struct Connection *conn)
Clear out any queued data.
Definition: socket.c:313
int mutt_socket_read(struct Connection *conn, char *buf, size_t len)
Read from a Connection.
Definition: socket.c:125
int mutt_socket_open(struct Connection *conn)
Simple wrapper.
Definition: socket.c:76
static int socket_preconnect(void)
Execute a command before opening a socket.
Definition: socket.c:50
int mutt_socket_write(struct Connection *conn, const char *buf, size_t len)
Write to a Connection.
Definition: socket.c:138
int mutt_socket_readln_d(char *buf, size_t buflen, struct Connection *conn, int dbg)
Read a line from a socket.
Definition: socket.c:246
Low-level socket handling.
ConnectionType
Type of connection.
Definition: socket.h:35
@ MUTT_CONNECTION_SSL
SSL/TLS-encrypted connection.
Definition: socket.h:38
@ MUTT_CONNECTION_TUNNEL
Tunnelled connection.
Definition: socket.h:37
Handling of SSL encryption.
char host[128]
Server to login to.
Definition: connaccount.h:54
unsigned short port
Port to connect to.
Definition: connaccount.h:58
char inbuf[1024]
Buffer for incoming traffic.
Definition: connection.h:52
int(* poll)(struct Connection *conn, time_t wait_secs)
Definition: connection.h:106
int(* write)(struct Connection *conn, const char *buf, size_t count)
Definition: connection.h:93
unsigned int ssf
Security strength factor, in bits (see notes)
Definition: connection.h:51
int bufpos
Current position in the buffer.
Definition: connection.h:53
int(* close)(struct Connection *conn)
Definition: connection.h:117
int available
Amount of data waiting to be read.
Definition: connection.h:55
struct ConnAccount account
Account details: username, password, etc.
Definition: connection.h:50
int(* open)(struct Connection *conn)
Definition: connection.h:67
int fd
Socket file descriptor.
Definition: connection.h:54
int(* read)(struct Connection *conn, char *buf, size_t count)
Definition: connection.h:80
Container for Accounts, Notifications.
Definition: neomutt.h:37
struct ConfigSubset * sub
Inherited config items.
Definition: neomutt.h:39