ze-filter  (ze-filter-0.8.0-develop-180218)
ze-client.c
Go to the documentation of this file.
1 /*
2  *
3  * ze-filter - Mail Server Filter for sendmail
4  *
5  * Copyright (c) 2001-2018 - Jose-Marcio Martins da Cruz
6  *
7  * Auteur : Jose Marcio Martins da Cruz
8  * jose.marcio.mc@gmail.org
9  *
10  * Historique :
11  * Creation : Thu Aug 7 17:05:57 CEST 2008
12  *
13  * This program is free software, but with restricted license :
14  *
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * More details about ze-filter license can be found at ze-filter
21  * web site : http://foss.jose-marcio.org
22  */
23 
24 
25 #include <ze-sys.h>
26 #include <ze-filter.h>
27 #include <ze-client.h>
28 
29 /* ****************************************************************************
30  * *
31  * *
32  **************************************************************************** */
33 #define MAX_TOUT 4
34 
35 #define T_INACTIVITY 120
36 #define MAX_ERRORS 16
37 
38 #define TOUT_I 1000
39 #define TOUT_C 100
40 
41 static char *tcp_prefix(char *);
42 static char *udp_prefix(char *);
43 static char *unix_prefix(char *);
44 
45 /* ****************************************************************************
46  * *
47  * *
48  **************************************************************************** */
49 static int
50 inet_client_connect(node, service, socktype, client, to)
51  char *node;
52  char *service;
53  int socktype;
54  client_T *client;
55  int to;
56 {
57  int sfd = -1;
58  struct addrinfo hints;
59  struct addrinfo *addrinfo, *rp;
60  int s;
61 
62  ASSERT(node != NULL || service != NULL);
63 
64  if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
65  socktype = SOCK_STREAM;
66 
67  ZE_MessageInfo(15, "inet_client_connect : %s %s/%s",
68  STRNULL(node, "NODE???"), STRNULL(service, "SERVICE???"),
69  socktype == SOCK_STREAM ? "tcp" : "udp");
70 
71  memset(&hints, 0, sizeof (struct addrinfo));
72  hints.ai_family = AF_UNSPEC;
73  hints.ai_socktype = socktype;
74  hints.ai_flags = AI_PASSIVE;
75  hints.ai_protocol = 0;
76 
77  s = getaddrinfo(node, service, &hints, &addrinfo);
78  if (s != 0)
79  {
80  ZE_LogSysError("getaddrinfo: %s", gai_strerror(s));
81  goto fin;
82  }
83 
84  for (rp = addrinfo; rp != NULL; rp = rp->ai_next)
85  {
86  sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
87  if (sfd == -1)
88  continue;
89 
90  if (connect_timed(sfd, rp->ai_addr, rp->ai_addrlen, to) != -1)
91  break;
92 
93  close(sfd);
94  sfd = -1;
95  }
96 
97  if (rp == NULL || sfd < 0)
98  {
99  freeaddrinfo(addrinfo);
100  goto fin;
101  }
102 
103  if (client != NULL && rp != NULL)
104  {
105  client->family = rp->ai_family;
106  client->protocol = rp->ai_protocol;
107  client->socktype = rp->ai_socktype;
108  client->sd = sfd;
109 #if 0
110  strlcpy(client->spec, spec, sizeof (client->spec));
111 #endif
112  }
113 
114  freeaddrinfo(addrinfo);
115 
116 fin:
117  return sfd;
118 }
119 
120 
121 /* ****************************************************************************
122  * *
123  * *
124  **************************************************************************** */
125 int
126 client_connect(client, spec, to)
127  client_T *client;
128  char *spec;
129  int to;
130 {
131  char *p, *s;
132  int fd = -1;
133 
134  int sargc;
135  char *sargv[4];
136  int i;
137  char sbuf[256];
138 
139  if ((spec == NULL) || (strlen(spec) == 0))
140  return -1;
141 
142  strlcpy(sbuf, spec, sizeof (sbuf));
143  sargc = zeStr2Tokens(sbuf, 4, sargv, " ,");
144 
145  for (i = 0; i < sargc; i++)
146  {
147  ZE_MessageInfo(15, " INET server to connect : %s", sargv[i]);
148 
149  if ((s = tcp_prefix(sargv[i])) != NULL)
150  {
151  char sport[32], shost[128];
152  int argc;
153  char *argv[4];
154  char tbuf[256];
155 
156  p = sargv[i] + strlen(s);
157 
158  memset(sport, 0, sizeof (sport));
159  memset(shost, 0, sizeof (shost));
160 
161  strlcpy(tbuf, p, sizeof (tbuf));
162 
163  argc = zeStr2Tokens(tbuf, 4, argv, "@");
164  if (argc == 0)
165  goto fin;
166 
167  strlcpy(sport, argv[0], sizeof (sport));
168  if (argc > 1)
169  strlcpy(shost, argv[1], sizeof (shost));
170  else
171  strlcpy(shost, "127.0.0.1", sizeof (shost));
172 
173  ZE_MessageInfo(10, "Connecting to inet server [%s] on port [%s/tcp]",
174  shost, sport);
175 
176  fd = inet_client_connect(shost, sport, SOCK_STREAM, client, to);
177  if (fd >= 0)
178  break;
179  }
180  }
181 
182 #if 0
183  if (client->sd >= 0)
184  client_flush_read(client);
185 #endif
186 
187 fin:
188  if (client != NULL)
189  {
190  if (fd < 0)
191  {
192  client->nerr++;
193  client->lasterr = time(NULL);
194  } else
195  {
196  client->nerr = 0;
197  client->lasterr = (time_t) 0;
198  }
199  }
200 
201  return fd;
202 }
203 
204 /* ****************************************************************************
205  * *
206  * *
207  **************************************************************************** */
208 bool
210  client_T *client;
211 {
212  if (client == NULL)
213  return FALSE;
214 
215  if (client->signature != SIGNATURE) {
216  ZE_LogMsgError(0, "client structure not initialized");
217  return FALSE;
218  }
219 
220  if (client->sd >= 0)
221  return TRUE;
222 
223  return FALSE;
224 }
225 
226 /* ****************************************************************************
227  * *
228  * *
229  **************************************************************************** */
230 bool
231 client_disconnect(client, incerr)
232  client_T *client;
233  bool incerr;
234 {
235  if (client != NULL) {
236  if (client->sd >= 0)
237  {
238  shutdown(client->sd, SHUT_RDWR);
239  close(client->sd);
240 
241  client->sd = -1;
242  client->family = 0;
243  client->protocol = 0;
244  client->socktype = 0;
245  }
246  if (incerr) {
247  client->nerr++;
248  client->lasterr = time(NULL);
249  } else {
250  client->nerr = 0;
251  client->lasterr = (time_t) 0;
252  }
253  }
254 
255  return TRUE;
256 }
257 
258 /* ****************************************************************************
259  * *
260  * *
261  **************************************************************************** */
262 bool
263 client_send(client, buf, size)
264  client_T *client;
265  char *buf;
266  size_t size;
267 {
268  char *p;
269  size_t sz;
270  time_t tout = TOUT_I;
271  int nto = 0;
272  bool result = TRUE;
273 
274  p = buf;
275  sz = size;
276 
277  for (;;)
278  {
279  int r;
280 
281  r = jfd_ready(client->sd, ZE_SOCK_WRITE, tout);
282 
283  if (r == ZE_SOCK_ERROR)
284  {
285  ZE_LogSysError("send error");
286  result = FALSE;
287  break;
288  }
289 
290  if (r == ZE_SOCK_TIMEOUT)
291  {
292  if (nto++ > MAX_TOUT) {
293  ZE_LogSysError("send error");
294  break;
295  }
296  continue;
297  }
298  nto = 0;
299 
300  if (r == ZE_SOCK_READY)
301  {
302  size_t n;
303 
304  tout = TOUT_C;
305  n = sendto(client->sd, p, sz - 1, 0, NULL, 0);
306 
307  if (n > 0)
308  {
309  p += n;
310  sz -= n;
311  *p = '\0';
312 #if 0
313  if (sz > 0)
314  continue;
315 #endif
316  }
317 
318  if (n < 0)
319  {
320  if (errno == EINTR)
321  continue;
322 
323  /* an error occured */
324  ZE_LogSysError("recvfrom error");
325  client_disconnect(client, TRUE);
326  result = FALSE;
327  goto fin;
328  }
329 
330  if (n == 0)
331  {
332  /* an error occured */
333  ZE_LogMsgError(0, "greyd server performed an orderly shutdown");
334  client_disconnect(client, TRUE);
335  result = FALSE;
336  goto fin;
337  }
338  }
339  break;
340  }
341 
342 #if 0
343  clear_errors();
344 #endif
345 
346 fin:
347  return result;
348 }
349 
350 /* ****************************************************************************
351  * *
352  * *
353  **************************************************************************** */
354 bool
355 client_recv(client, buf, size)
356  client_T *client;
357  char *buf;
358  size_t size;
359 {
360  char *p;
361  size_t sz;
362  time_t tout = TOUT_I;
363  int nto = 0;
364 
365  bool result = TRUE;
366 
367  if (buf == NULL || size <= 0)
368  return FALSE;
369 
370  memset(buf, 0, size);
371  p = buf;
372  sz = size - 1;
373 
374  for (;;)
375  {
376  int r;
377 
378  errno = 0;
379  r = jfd_ready(client->sd, ZE_SOCK_READ, tout);
380 
381  if (r == ZE_SOCK_ERROR)
382  {
383  result = FALSE;
384  ZE_LogSysError("recvfrom error 1");
385  break;
386  }
387 
388  if (r == ZE_SOCK_TIMEOUT)
389  {
390  result = (strlen(buf) > 0);
391  break;
392  }
393 
394  if (r == ZE_SOCK_READY)
395  {
396  size_t n;
397 
398  tout = TOUT_C;
399  n = recvfrom(client->sd, p, sz, 0, NULL, NULL);
400  if (n > 0)
401  {
402  p += n;
403  sz -= n;
404  *p = '\0';
405 
406  break;
407  continue;
408  }
409 
410  if (n < 0)
411  {
412  if (errno == EINTR)
413  continue;
414 
415  /* an error occured */
416  ZE_LogSysError("recvfrom error 3");
417  client_disconnect(client, TRUE);
418  result = FALSE;
419  goto fin;
420  }
421 
422  if (n == 0)
423  {
424  /* an error occured */
425  ZE_LogMsgError(0, "greyd server performed an orderly shutdown");
426  client_disconnect(client, TRUE);
427  result = FALSE;
428  goto fin;
429  }
430  }
431  break;
432  }
433 
434 #if 0
435  clear_errors();
436 #endif
437 
438 fin:
439  return result;
440 }
441 
442 /* ****************************************************************************
443  * *
444  * *
445  **************************************************************************** */
446 bool
447 client_readln(client, buf, size)
448  client_T *client;
449  char *buf;
450  size_t size;
451 {
452  char *p;
453  size_t sz;
454  time_t tout = TOUT_I;
455  int nto = 0;
456 
457  bool result = TRUE;
458 
459  if (buf == NULL || size <= 0)
460  return FALSE;
461 
462  memset(buf, 0, size);
463  p = buf;
464  sz = size - 1;
465 
466  for (;;)
467  {
468  int r;
469 
470  errno = 0;
471  r = jfd_ready(client->sd, ZE_SOCK_READ, tout);
472 
473  if (r == ZE_SOCK_ERROR)
474  {
475  result = FALSE;
476  ZE_LogSysError("recvfrom error 1");
477  break;
478  }
479 
480  if (r == ZE_SOCK_TIMEOUT)
481  {
482  result = (strlen(buf) > 0);
483  break;
484  }
485 
486  if (r == ZE_SOCK_READY)
487  {
488  size_t n;
489 
490  tout = TOUT_C;
491  n = recvfrom(client->sd, p, 1, MSG_DONTWAIT, NULL, NULL);
492  if (n > 0)
493  {
494  if (*p == '\r')
495  continue;
496 
497  if (*p == '\n') {
498  *p = '\0';
499  break;
500  }
501  *++p = '\0';
502  sz--;
503  continue;
504  }
505 
506  if (n < 0)
507  {
508 #if 0
509  if (errno == EINTR)
510  continue;
511 #else
512  if (errno == EINTR || errno == EAGAIN)
513  continue;
514 #endif
515  /* an error occured */
516  ZE_LogSysError("recvfrom error 3");
517  client_disconnect(client, TRUE);
518  result = FALSE;
519  goto fin;
520  }
521 
522  if (n == 0)
523  {
524  /* an error occured */
525  ZE_LogMsgError(0, "greyd server performed an orderly shutdown");
526  client_disconnect(client, TRUE);
527  result = FALSE;
528  goto fin;
529  }
530  }
531  break;
532  }
533  *p = '\0';
534 #if 0
535  clear_errors();
536 #endif
537 
538 fin:
539  return result;
540 }
541 
542 
543 /* ****************************************************************************
544  * *
545  * *
546  **************************************************************************** */
547 
548 bool
550  client_T *client;
551 {
552  int sd;
553  bool result = TRUE;
554  char buf[256];
555 
556  if (client == NULL)
557  return FALSE;
558 
559  sd = client->sd;
560  /* empty input buffer before asking something */
561  for (;;)
562  {
563  int r;
564  size_t sz;
565 
566  r = jfd_ready(sd, ZE_SOCK_READ, 5);
567 
568  if (r == ZE_SOCK_ERROR)
569  {
570  ZE_LogSysError("error");
571  client_disconnect(client, TRUE);
572  result = FALSE;
573  goto fin;
574  }
575 
576  if (r != ZE_SOCK_READY)
577  break;
578 
579  sz = recvfrom(sd, buf, sizeof (buf), 0, NULL, NULL);
580 
581  if (sz > 0)
582  continue;
583  if (sz < 0)
584  ZE_LogSysError("recvfrom error");
585  if (sz == 0)
586  ZE_LogMsgError(0, "connection closed by server");
587  client_disconnect(client, TRUE);
588  result = FALSE;
589  break;
590  }
591 
592 fin:
593  return result;
594 }
595 
596 
597 /* ****************************************************************************
598  * *
599  * *
600  **************************************************************************** */
601 
602 /*
603 **
604 **
605 **
606 **
607 **
608 **
609 */
610 
611 
612 /* ****************************************************************************
613  * *
614  * *
615  **************************************************************************** */
616 static void
617 set_errors_count(client, ok)
618  client_T *client;
619  bool ok;
620 {
621  if (client != NULL)
622  {
623  if (ok)
624  {
625  client->nerr = 0;
626  client->lasterr = (time_t) 0;
627  } else
628  {
629 
630  }
631  }
632 }
633 
634 /* ****************************************************************************
635  * *
636  * *
637  **************************************************************************** */
638 int
639 connect_timed(sockfd, sock, socklen, to)
640  int sockfd;
641  struct sockaddr *sock;
642  socklen_t socklen;
643  int to;
644 {
645  int flags, n, error;
646  socklen_t len;
647  fd_set rset, wset;
648  struct timeval tval;
649 
650  if ((flags = fcntl(sockfd, F_GETFL, 0)) < 0)
651  {
652  error = errno;
653  ZE_LogSysError("fcntl getting sockfd flags error");
654 
655  goto fin;
656  }
657 
658  if (fcntl(sockfd, F_SETFL, flags | O_NONBLOCK) < 0)
659  {
660  error = errno;
661  ZE_LogSysError("fcntl setting sockfd flags error");
662 
663  goto fin;
664  }
665 
666  error = 0;
667  if ((n = connect(sockfd, sock, socklen)) < 0)
668  {
669  if (errno != EINPROGRESS)
670  {
671  ZE_LogSysError("connect error");
672  return -1;
673  }
674  }
675 
676  if (n == 0)
677  goto fin;
678 
679  FD_ZERO(&rset);
680  FD_SET(sockfd, &rset);
681  wset = rset;
682 
683  tval.tv_sec = to;
684  tval.tv_usec = 0;
685 
686  if ((n = select(sockfd + 1, &rset, &wset, NULL, &tval)) == 0)
687  {
688  /* timeout */
689  ZE_LogMsgError(0, "Connection establishing timed out");
690  close(sockfd);
691  errno = ETIMEDOUT;
692  return -1;
693  }
694 
695  if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset))
696  {
697  len = sizeof (error);
698  if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
699  {
700  ZE_LogSysError("getsockopt error");
701  return -1; /* Solaris pending error */
702  }
703  } else
704  {
705  ZE_LogSysError("select error");
706  return -1;
707  }
708 
709 fin:
710  if (fcntl(sockfd, F_SETFL, flags) < 0)
711  {
712  error = errno;
713  ZE_LogSysError("fcntl setting sockfd flags error");
714  }
715 
716  if (error != 0)
717  {
718  close(sockfd);
719  errno = error;
720  return -1;
721  }
722 
723  return 0;
724 }
725 
726 
727 /* ****************************************************************************
728  * *
729  * *
730  **************************************************************************** */
731 #define STRPREFIX(s,pfx) STRNCASEEQUAL((s),(pfx),strlen(pfx))
732 
733 static char *
734 tcp_prefix(spec)
735  char *spec;
736 {
737  if (STRPREFIX(spec, "inet:"))
738  return "inet:";
739  if (STRPREFIX(spec, "tcp:"))
740  return "tcp:";
741  if (STRPREFIX(spec, "stream:"))
742  return "stream:";
743 
744  return NULL;
745 }
746 
747 static char *
748 udp_prefix(spec)
749  char *spec;
750 {
751  if (STRPREFIX(spec, "udp:"))
752  return "udp:";
753  if (STRPREFIX(spec, "dgram:"))
754  return "dgram:";
755 
756  return NULL;
757 }
758 
759 static char *
760 unix_prefix(spec)
761  char *spec;
762 {
763  if (STRPREFIX(spec, "unix:"))
764  return "unix:";
765  if (STRPREFIX(spec, "local:"))
766  return "local:";
767 
768  return NULL;
769 }
int socklen_t
Definition: ze-sys.h:534
#define MAX_TOUT
Definition: ze-client.c:33
#define ASSERT(a)
Definition: macros.h:27
int signature
Definition: ze-client.h:38
#define ZE_SOCK_WRITE
Definition: ze-inet.h:58
#define STRPREFIX(s, pfx)
Definition: ze-client.c:731
bool client_send(client_T *client, char *buf, size_t size)
Definition: ze-client.c:263
#define TOUT_I
Definition: ze-client.c:38
#define STRNULL(x, r)
Definition: macros.h:81
bool ok
Definition: ze-connopen.c:59
int jfd_ready(int, bool, long)
Definition: ze-inet.c:529
#define FALSE
Definition: macros.h:160
#define strlcpy
Definition: zeString.h:32
#define ZE_LogMsgError(level,...)
Definition: zeSyslog.h:113
#define ZE_SOCK_TIMEOUT
Definition: ze-inet.h:62
char spec[CLIENT_SPEC_LEN]
Definition: ze-client.h:50
#define TOUT_C
Definition: ze-client.c:39
int zeStr2Tokens(char *, int, char **, char *)
Definition: zeStrings.c:610
int family
Definition: ze-client.h:45
int protocol
Definition: ze-client.h:46
int sd
Definition: ze-client.h:44
time_t lasterr
Definition: ze-client.h:42
int connect_timed(int sockfd, struct sockaddr *sock, socklen_t socklen, int to)
Definition: ze-client.c:639
int socktype
Definition: ze-client.h:47
#define ZE_MessageInfo(level,...)
Definition: zeSyslog.h:90
#define TRUE
Definition: macros.h:157
#define ZE_LogSysError(...)
Definition: zeSyslog.h:129
#define ZE_SOCK_ERROR
Definition: ze-inet.h:60
bool client_disconnect(client_T *client, bool incerr)
Definition: ze-client.c:231
int client_connect(client_T *client, char *spec, int to)
Definition: ze-client.c:126
bool client_recv(client_T *client, char *buf, size_t size)
Definition: ze-client.c:355
int nerr
Definition: ze-client.h:41
#define ZE_SOCK_READ
Definition: ze-inet.h:57
bool client_flush_read(client_T *client)
Definition: ze-client.c:549
#define SIGNATURE
Definition: ze-libjc.h:75
#define ZE_SOCK_READY
Definition: ze-inet.h:61
bool client_readln(client_T *client, char *buf, size_t size)
Definition: ze-client.c:447
bool client_check_state(client_T *client)
Definition: ze-client.c:209