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