2
* Soft: Keepalived is a failover program for the LVS project
3
* <www.linuxvirtualserver.org>. It monitor & manipulate
4
* a loadbalanced server pool using multi-layer checks.
6
* Part: SMTP CHECK. Check an SMTP-server.
8
* Version: $Id: check_smtp.c,v 1.1.11 2005/03/01 01:22:13 acassen Exp $
10
* Authors: Jeremy Rumpf, <jrumpf@heavyload.net>
11
* Alexandre Cassen, <acassen@linux-vs.org>
13
* This program is distributed in the hope that it will be useful,
14
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16
* See the GNU General Public License for more details.
18
* This program is free software; you can redistribute it and/or
19
* modify it under the terms of the GNU General Public License
20
* as published by the Free Software Foundation; either version
21
* 2 of the License, or (at your option) any later version.
23
* Copyright (C) 2001-2005 Alexandre Cassen, <acassen@linux-vs.org>
28
#include "check_smtp.h"
29
#include "check_api.h"
31
#include "ipwrapper.h"
36
int smtp_connect_thread(thread *);
38
/* module variables */
39
static smtp_host *default_host = NULL;
42
* Used as a callback from free_list() to free all
43
* the list elements in smtp_checker->host before we
44
* free smtp_checker itself.
47
smtp_free_host(void *data)
52
/* Used as a callback from the checker api, queue_checker(),
53
* to free up a checker entry and all its associated data.
56
free_smtp_check(void *data)
58
smtp_checker *smtp_chk = CHECKER_DATA(data);
59
free_list(smtp_chk->host);
60
FREE(smtp_chk->helo_name);
66
* Used as a callback from dump_list() to print out all
67
* the list elements in smtp_checker->host.
70
smtp_dump_host(void *data)
72
smtp_host *smtp_hst = data;
73
syslog(LOG_INFO, " Checked ip = %s", inet_ntop2(smtp_hst->ip));
74
syslog(LOG_INFO, " port = %d", ntohs(smtp_hst->port));
76
syslog(LOG_INFO, " bindto = %s", inet_ntop2(smtp_hst->bindto));
80
* Callback for whenever we've been requested to dump our
84
dump_smtp_check(void *data)
86
smtp_checker *smtp_chk = CHECKER_DATA(data);
87
syslog(LOG_INFO, " Keepalive method = SMTP_CHECK");
88
syslog(LOG_INFO, " helo = %s", smtp_chk->helo_name);
89
syslog(LOG_INFO, " timeout = %ld", smtp_chk->timeout/TIMER_HZ);
90
syslog(LOG_INFO, " retry = %d", smtp_chk->retry);
91
syslog(LOG_INFO, " delay before retry = %ld", smtp_chk->db_retry/TIMER_HZ);
92
dump_list(smtp_chk->host);
95
/* Allocates a default host structure */
99
checker *chk = LIST_TAIL_DATA(checkers_queue);
102
/* Allocate the new host data structure */
103
new = (smtp_host *)MALLOC(sizeof(smtp_host));
106
* By default we set the ip to connect to as the same ip as the current real server
107
* in the rs config. This might be overridden later on by a "connect_ip" keyword.
109
new->ip = CHECKER_RIP(chk);
110
new->port = htons(SMTP_DEFAULT_PORT);
115
* Callback for whenever an SMTP_CHECK keyword is encountered
116
* in the config file.
119
smtp_check_handler(vector strvec)
121
smtp_checker *smtp_chk = (smtp_checker *)MALLOC(sizeof(smtp_checker));
124
* Set something sane for the default HELO banner
125
* May be overridden by a "helo_name" keyword later.
127
smtp_chk->helo_name = (char *)MALLOC(strlen(SMTP_DEFAULT_HELO) + 1);
128
memcpy(smtp_chk->helo_name, SMTP_DEFAULT_HELO, strlen(SMTP_DEFAULT_HELO) + 1);
130
/* some other sane values */
131
smtp_chk->timeout = 5 * TIMER_HZ;
132
smtp_chk->db_retry = 1 * TIMER_HZ;
136
* Have the checker queue code put our checker into the checkers_queue
139
* queue_checker(void (*free) (void *), void (*dump) (void *),
140
* int (*launch) (struct _thread *),
143
queue_checker(free_smtp_check, dump_smtp_check, smtp_connect_thread,
147
* Last, allocate/setup the list that will hold all the per host
148
* configuration structures. We'll set a "default host", which
149
* is the same ip as the real server. If there are additional "host"
150
* sections in the config, the default will be deleted and overridden.
151
* This must come after queue_checker()!
153
smtp_chk->host = alloc_list(smtp_free_host, smtp_dump_host);
155
default_host = smtp_alloc_host();
156
list_add(smtp_chk->host, default_host);
160
* Callback for whenever the "host" keyword is encountered
161
* in the config file.
164
smtp_host_handler(vector strvec)
166
smtp_checker *smtp_chk = CHECKER_GET();
169
* If the default host is still allocated, delete it
170
* before we stick user defined hosts in the list.
173
list_del(smtp_chk->host, default_host);
178
/* add an empty host to the list, smtp_checker->host */
179
list_add(smtp_chk->host, smtp_alloc_host());
182
/* "connect_ip" keyword */
184
smtp_ip_handler(vector strvec)
186
smtp_checker *smtp_chk = CHECKER_GET();
187
smtp_host *smtp_hst = LIST_TAIL_DATA(smtp_chk->host);
188
inet_ston(VECTOR_SLOT(strvec, 1), &smtp_hst->ip);
191
/* "connect_port" keyword */
193
smtp_port_handler(vector strvec)
195
smtp_checker *smtp_chk = CHECKER_GET();
196
smtp_host *smtp_hst = LIST_TAIL_DATA(smtp_chk->host);
197
smtp_hst->port = htons(CHECKER_VALUE_INT(strvec));
200
/* "helo_name" keyword */
202
smtp_helo_name_handler(vector strvec)
204
smtp_checker *smtp_chk = CHECKER_GET();
205
smtp_chk->helo_name = CHECKER_VALUE_STRING(strvec);
208
/* "connect_timeout" keyword */
210
smtp_timeout_handler(vector strvec)
212
smtp_checker *smtp_chk = CHECKER_GET();
213
smtp_chk->timeout = CHECKER_VALUE_INT(strvec) * TIMER_HZ;
216
/* "retry" keyword */
218
smtp_retry_handler(vector strvec)
220
smtp_checker *smtp_chk = CHECKER_GET();
221
smtp_chk->retry = CHECKER_VALUE_INT(strvec);
224
/* "delay_before_retry" keyword */
226
smtp_db_retry_handler(vector strvec)
228
smtp_checker *smtp_chk = CHECKER_GET();
229
smtp_chk->db_retry = CHECKER_VALUE_INT(strvec) * TIMER_HZ;
232
/* "bindto" keyword */
234
smtp_bindto_handler(vector strvec)
236
smtp_checker *smtp_chk = CHECKER_GET();
237
smtp_host *smtp_hst = LIST_TAIL_DATA(smtp_chk->host);
238
inet_ston(VECTOR_SLOT(strvec, 1), &smtp_hst->bindto);
241
/* Config callback installer */
243
install_smtp_check_keyword(void)
246
* Notify the config log parser that we need to be notified via
247
* callbacks when the following keywords are encountered in the
248
* keepalive.conf file.
250
install_keyword("SMTP_CHECK", &smtp_check_handler);
252
install_keyword("helo_name", &smtp_helo_name_handler);
253
install_keyword("connect_timeout", &smtp_timeout_handler);
254
install_keyword("delay_before_retry", &smtp_db_retry_handler);
255
install_keyword("retry", &smtp_retry_handler);
256
install_keyword("host", &smtp_host_handler);
258
install_keyword("connect_ip", &smtp_ip_handler);
259
install_keyword("connect_port", &smtp_port_handler);
260
install_keyword("bindto", &smtp_bindto_handler);
261
install_sublevel_end();
262
install_sublevel_end();
266
* Final handler. Determines if we need a retry or not.
267
* Also has to make a decision if we need to bring the resulting
268
* service down in case of error.
271
smtp_final(thread *thread_obj, int error, const char *format, ...)
273
checker *chk = THREAD_ARG(thread_obj);
274
smtp_checker *smtp_chk = CHECKER_ARG(chk);
275
char error_buff[512];
279
/* Error or no error we should always have to close the socket */
280
close(thread_obj->u.fd);
282
/* If we're here, an attempt HAS been made already for the current host */
283
smtp_chk->attempts++;
286
/* Always syslog the error when the real server is up */
287
if (svr_checker_up(chk->id, chk->rs)) {
288
if (format != NULL) {
289
memcpy(error_buff, "SMTP_CHECK ", 11);
290
va_start(varg_list, format);
291
vsnprintf(error_buff + 11, 512 - 11, format, varg_list);
293
error_buff[512 - 1] = '\0';
295
syslog(LOG_INFO, error_buff);
297
syslog(LOG_INFO, "SMTP_CHECK Unknown error");
302
* If we still have retries left, try this host again by
303
* scheduling the main thread to check it again after the
304
* configured backoff delay. Otherwise down the RS.
306
if (smtp_chk->attempts < smtp_chk->retry) {
307
thread_add_timer(thread_obj->master, smtp_connect_thread, chk,
313
* No more retries, pull the real server from the virtual server.
314
* Only smtp_alert if it wasn't previously down. It should
315
* be noted that smtp_alert makes a copy of the string arguments, so
316
* we don't have to keep them statically allocated.
318
if (svr_checker_up(chk->id, chk->rs)) {
319
if (format != NULL) {
320
snprintf(smtp_buff, 542, "=> CHECK failed on service : %s <=",
323
snprintf(smtp_buff, 542, "=> CHECK failed on service <=");
326
smtp_buff[542 - 1] = '\0';
327
smtp_alert(chk->rs, NULL, NULL, "DOWN", smtp_buff);
330
update_svr_checker_state(DOWN, chk->id, chk->vs, chk->rs);
332
/* Reset everything back to the first host in the list */
333
smtp_chk->attempts = 0;
334
smtp_chk->host_ctr = 0;
336
/* Reschedule the main thread using the configured delay loop */;
337
thread_add_timer(thread_obj->master, smtp_connect_thread, chk, chk->vs->delay_loop);
343
* Ok this host was successful, increment to the next host in the list
344
* and reset the attempts counter. We'll then reschedule the main thread again.
345
* If host_ctr exceeds the number of hosts in the list, http_main_thread will
346
* take note and bring up the real server as well as inject the delay_loop.
348
smtp_chk->attempts = 0;
349
smtp_chk->host_ctr++;
351
thread_add_timer(thread_obj->master, smtp_connect_thread, chk, 1);
356
* Zeros out the rx/tx buffer
359
smtp_clear_buff(thread *thread_obj)
361
checker *chk = THREAD_ARG(thread_obj);
362
smtp_checker *smtp_chk = CHECKER_ARG(chk);
363
memset(smtp_chk->buff, 0, SMTP_BUFF_MAX);
364
smtp_chk->buff_ctr = 0;
368
* One thing to note here is we do a very cheap check for a newline.
369
* We could receive two lines (with two newline characters) in a
370
* single packet, but we don't care. We are only looking at the
371
* SMTP response codes at the beginning anyway.
374
smtp_get_line_cb(thread *thread_obj)
376
checker *chk = THREAD_ARG(thread_obj);
377
smtp_checker *smtp_chk = CHECKER_ARG(chk);
378
smtp_host *smtp_hst = smtp_chk->host_ptr;
381
/* Handle read timeout */
382
if (thread_obj->type == THREAD_READ_TIMEOUT) {
383
smtp_final(thread_obj, 1, "Read timeout from server [%s:%d]",
384
inet_ntop2(smtp_hst->ip), ntohs(smtp_hst->port));
388
/* wrap the buffer, if full, by clearing it */
389
if (SMTP_BUFF_MAX - smtp_chk->buff_ctr <= 0) {
390
syslog(LOG_INFO, "SMTP_CHECK Buffer overflow reading from server [%s:%d]. "
391
"Increase SMTP_BUFF_MAX in smtp_check.h",
392
inet_ntop2(smtp_hst->ip), ntohs(smtp_hst->port));
393
smtp_clear_buff(thread_obj);
396
/* Set descriptor non blocking */
397
f = fcntl(thread_obj->u.fd, F_GETFL, 0);
398
fcntl(thread_obj->u.fd, F_SETFL, f | O_NONBLOCK);
401
r = read(thread_obj->u.fd, smtp_chk->buff + smtp_chk->buff_ctr,
402
SMTP_BUFF_MAX - smtp_chk->buff_ctr);
404
if (r == -1 && (errno == EAGAIN || errno == EINTR)) {
405
thread_add_read(thread_obj->master, smtp_get_line_cb, chk,
406
thread_obj->u.fd, smtp_chk->timeout);
407
fcntl(thread_obj->u.fd, F_SETFL, f);
410
smtp_chk->buff_ctr += r;
412
/* restore descriptor flags */
413
fcntl(thread_obj->u.fd, F_SETFL, f);
415
/* check if we have a newline, if so, callback */
416
for (x = 0; x < SMTP_BUFF_MAX; x++) {
417
if (smtp_chk->buff[x] == '\n') {
418
smtp_chk->buff[SMTP_BUFF_MAX - 1] = '\0';
420
DBG("SMTP_CHECK [%s:%d] < %s", inet_ntop2(smtp_hst->ip),
421
ntohs(smtp_hst->port), smtp_chk->buff);
423
(smtp_chk->buff_cb)(thread_obj);
430
* If the connection was closed or there was
431
* some sort of error, notify smtp_final()
434
smtp_final(thread_obj, 1, "Read failure from server [%s:%d]",
435
inet_ntop2(smtp_hst->ip), ntohs(smtp_hst->port));
440
* Last case, we haven't read enough data yet
441
* to pull a newline. Schedule ourselves for
444
thread_add_read(thread_obj->master, smtp_get_line_cb, chk,
445
thread_obj->u.fd, smtp_chk->timeout);
450
* Ok a caller has asked us to asyncronously schedule a single line
451
* to be received from the server. They have also passed us a call back
452
* function that we'll call once we have the newline. If something bad
453
* happens, the caller assumes we'll pass the error off to smtp_final(),
454
* which will either down the real server or schedule a retry. The
455
* function smtp_get_line_cb is what does the dirty work since the
456
* sceduler can only accept a single *thread argument.
459
smtp_get_line(thread *thread_obj, int (*callback) (struct _thread *))
461
checker *chk = THREAD_ARG(thread_obj);
462
smtp_checker *smtp_chk = CHECKER_ARG(chk);
464
/* clear the buffer */
465
smtp_clear_buff(thread_obj);
467
/* set the callback */
468
smtp_chk->buff_cb = callback;
470
/* schedule the I/O with our helper function */
471
thread_add_read(thread_obj->master, smtp_get_line_cb, chk,
472
thread_obj->u.fd, smtp_chk->timeout);
477
* The scheduler function that puts the data out on the wire.
478
* All our data will fit into one packet, so we only check if
479
* the current write would block or not. If it wants to block,
480
* we'll return to the scheduler and try again later.
483
smtp_put_line_cb(thread *thread_obj)
485
checker *chk = THREAD_ARG(thread_obj);
486
smtp_checker *smtp_chk = CHECKER_ARG(chk);
487
smtp_host *smtp_hst = smtp_chk->host_ptr;
491
/* Handle read timeout */
492
if (thread_obj->type == THREAD_WRITE_TIMEOUT) {
493
smtp_final(thread_obj, 1, "Write timeout to server [%s:%d]",
494
inet_ntop2(smtp_hst->ip), ntohs(smtp_hst->port));
498
/* Set descriptor non blocking */
499
f = fcntl(thread_obj->u.fd, F_GETFL, 0);
500
fcntl(thread_obj->u.fd, F_SETFL, f | O_NONBLOCK);
503
w = write(thread_obj->u.fd, smtp_chk->buff, smtp_chk->buff_ctr);
505
if (w == -1 && (errno == EAGAIN || errno == EINTR)) {
506
thread_add_write(thread_obj->master, smtp_put_line_cb, chk,
507
thread_obj->u.fd, smtp_chk->timeout);
508
fcntl(thread_obj->u.fd, F_SETFL, f);
512
/* restore descriptor flags */
513
fcntl(thread_obj->u.fd, F_SETFL, f);
515
DBG("SMTP_CHECK [%s:%d] > %s", inet_ntop2(smtp_hst->ip),
516
ntohs(smtp_hst->port), smtp_chk->buff);
519
* If the connection was closed or there was
520
* some sort of error, notify smtp_final()
523
smtp_final(thread_obj, 1, "Write failure to server [%s:%d]",
524
inet_ntop2(smtp_hst->ip), ntohs(smtp_hst->port));
528
/* Execute the callback */
529
(smtp_chk->buff_cb)(thread_obj);
534
* This is the same as smtp_get_line() except that we're sending a
535
* line of data instead of receiving one.
538
smtp_put_line(thread *thread_obj, int (*callback) (struct _thread *))
540
checker *chk = THREAD_ARG(thread_obj);
541
smtp_checker *smtp_chk = CHECKER_ARG(chk);
543
smtp_chk->buff[SMTP_BUFF_MAX - 1] = '\0';
544
smtp_chk->buff_ctr = strlen(smtp_chk->buff);
546
/* set the callback */
547
smtp_chk->buff_cb = callback;
549
/* schedule the I/O with our helper function */
550
thread_add_write(thread_obj->master, smtp_put_line_cb, chk,
551
thread_obj->u.fd, smtp_chk->timeout);
556
* Ok, our goal here is to snag the status code out of the
557
* buffer and return it as an integer. If it's not legible,
561
smtp_get_status(thread *thread_obj)
563
checker *chk = THREAD_ARG(thread_obj);
564
smtp_checker *smtp_chk = CHECKER_ARG(chk);
565
char *buff = smtp_chk->buff;
567
/* First make sure they're all digits */
568
if (isdigit(buff[0]) && isdigit(buff[1]) &&
570
/* Truncate the string and convert */
579
* We have a connected socket and are ready to begin
580
* the conversation. This function schedules itself to
581
* be called via callbacks and tracking state in
582
* smtp_chk->state. Upon first calling, smtp_chk->state
583
* should be set to SMTP_START.
586
smtp_engine_thread(thread *thread_obj)
588
checker *chk = THREAD_ARG(thread_obj);
589
smtp_checker *smtp_chk = CHECKER_ARG(chk);
590
smtp_host *smtp_hst = smtp_chk->host_ptr;
592
switch (smtp_chk->state) {
594
/* First step, schedule to receive the greeting banner */
597
* Ok, if smtp_get_line schedules us back, we will
598
* have data to analyze. Otherwise, smtp_get_line
599
* will defer directly to smtp_final.
601
smtp_chk->state = SMTP_HAVE_BANNER;
602
smtp_get_line(thread_obj, smtp_engine_thread);
606
/* Second step, analyze banner, send HELO */
607
case SMTP_HAVE_BANNER:
608
/* Check for "220 some.mailserver.com" in the greeting */
609
if (smtp_get_status(thread_obj) != 220) {
610
smtp_final(thread_obj, 1, "Bad greeting banner from server [%s:%d]",
611
inet_ntop2(smtp_hst->ip), ntohs(smtp_hst->port));
617
* Schedule to send the HELO, smtp_put_line will
618
* defer directly to smtp_final on error.
620
smtp_chk->state = SMTP_SENT_HELO;
621
snprintf(smtp_chk->buff, SMTP_BUFF_MAX, "HELO %s\r\n",
622
smtp_chk->helo_name);
623
smtp_put_line(thread_obj, smtp_engine_thread);
627
/* Third step, schedule to read the HELO response */
629
smtp_chk->state = SMTP_RECV_HELO;
630
smtp_get_line(thread_obj, smtp_engine_thread);
634
/* Fourth step, analyze HELO return, send QUIT */
636
/* Check for "250 Please to meet you..." */
637
if (smtp_get_status(thread_obj) != 250) {
638
smtp_final(thread_obj, 1, "Bad HELO response from server [%s:%d]",
639
inet_ntop2(smtp_hst->ip), ntohs(smtp_hst->port));
644
smtp_chk->state = SMTP_SENT_QUIT;
645
snprintf(smtp_chk->buff, SMTP_BUFF_MAX, "QUIT\r\n");
646
smtp_put_line(thread_obj, smtp_engine_thread);
650
/* Fifth step, schedule to receive QUIT confirmation */
652
smtp_chk->state = SMTP_RECV_QUIT;
653
smtp_get_line(thread_obj, smtp_engine_thread);
657
/* Sixth step, wrap up success to smtp_final */
659
smtp_final(thread_obj, 0, NULL);
664
/* We shouldn't be here */
665
smtp_final(thread_obj, 1, "Unknown smtp engine state encountered");
670
* Second step in the process. Here we'll see if the connection
671
* to the host we're checking was successful or not.
674
smtp_check_thread(thread *thread_obj)
676
checker *chk = THREAD_ARG(thread_obj);
677
smtp_checker *smtp_chk = CHECKER_ARG(chk);
678
smtp_host *smtp_hst = smtp_chk->host_ptr;
681
status = tcp_socket_state(thread_obj->u.fd, thread_obj, smtp_hst->ip,
682
smtp_hst->port, smtp_check_thread);
685
smtp_final(thread_obj, 1, "Error connecting to server [%s:%d]",
686
inet_ntop2(smtp_hst->ip), ntohs(smtp_hst->port));
690
case connect_timeout:
691
smtp_final(thread_obj, 1, "Connection timeout to server [%s:%d]",
692
inet_ntop2(smtp_hst->ip), ntohs(smtp_hst->port));
696
case connect_success:
697
DBG("SMTP_CHECK Remote SMTP server [%s:%d] connected",
698
inet_ntop2(smtp_hst->ip), ntohs(smtp_hst->port));
700
/* Enter the engine at SMTP_START */
701
smtp_chk->state = SMTP_START;
702
smtp_engine_thread(thread_obj);
707
/* we shouldn't be here */
708
smtp_final(thread_obj, 1, "Unknown connection error to server [%s:%d]",
709
inet_ntop2(smtp_hst->ip), ntohs(smtp_hst->port));
714
* This is the main thread, where all the action starts.
715
* When the check daemon comes up, it goes down the checkers_queue
716
* and launches a thread for each checker that got registered.
717
* This is the callback/event function for that initial thread.
719
* It should be noted that we ARE responsible for sceduling
720
* ourselves to run again. It doesn't have to be right here,
721
* but eventually has to happen.
724
smtp_connect_thread(thread *thread_obj)
726
checker *chk = THREAD_ARG(thread_obj);
727
smtp_checker *smtp_chk = CHECKER_ARG(chk);
729
enum connect_result status;
732
/* Let's review our data structures.
734
* Thread is the structure used by the sceduler
735
* for sceduling many types of events. thread->arg in this
736
* case points to a checker structure. The checker
737
* structure holds data about the vs and rs configurations
738
* as well as the delay loop, etc. Each real server
739
* defined in the keepalived.conf will more than likely have
740
* a checker structure assigned to it. Each checker structure
741
* has a data element that is meant to hold per checker
742
* configurations. So thread->arg(checker)->data points to
743
* a smtp_checker structure. In the smtp_checker structure
744
* we hold global configuration data for the smtp check.
745
* Smtp_checker has a list of per host (smtp_host) configuration
746
* data in smtp_checker->host.
748
* So this whole thing looks like this:
749
* thread->arg(checker)->data(smtp_checker)->host(smtp_host)
751
* To make life simple, we'll break the structures out so
752
* that "chk" always points to the current checker structure,
753
* "smtp_chk" points to the current smtp_checker structure,
754
* and "smtp_hst" points to the current smtp_host structure.
758
* If we're disabled, we'll do nothing at all.
759
* But we still have to register ourselves again so
760
* we don't fall of the face of the earth.
762
if (!CHECKER_ENABLED(chk)) {
763
thread_add_timer(thread_obj->master, smtp_connect_thread, chk,
764
chk->vs->delay_loop);
769
* Set the internal host pointer to the host that well be
770
* working on. If it's NULL, we've successfully tested all hosts.
771
* We'll bring the service up (if it's not already), reset the host list,
772
* and insert the delay loop. When we get scheduled again the host list
773
* will be reset and we will continue on checking them one by one.
775
if ((smtp_chk->host_ptr = list_element(smtp_chk->host, smtp_chk->host_ctr)) == NULL) {
776
if (!svr_checker_up(chk->id, chk->rs)) {
777
syslog(LOG_INFO, "Remote SMTP server [%s:%d] succeed on service.",
778
inet_ntop2(CHECKER_RIP(chk)), ntohs(CHECKER_RPORT(chk)));
780
smtp_alert(chk->rs, NULL, NULL, "UP",
781
"=> CHECK succeed on service <=");
782
update_svr_checker_state(UP, chk->id, chk->vs, chk->rs);
785
smtp_chk->attempts = 0;
786
smtp_chk->host_ctr = 0;
787
smtp_chk->host_ptr = list_element(smtp_chk->host, 0);
789
thread_add_timer(thread_obj->master, smtp_connect_thread, chk, chk->vs->delay_loop);
793
smtp_hst = smtp_chk->host_ptr;
795
/* Create the socket, failling here should be an oddity */
796
if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
797
DBG("SMTP_CHECK connection failed to create socket.");
798
thread_add_timer(thread_obj->master, smtp_connect_thread, chk,
799
chk->vs->delay_loop);
803
status = tcp_bind_connect(sd, smtp_hst->ip, smtp_hst->port, smtp_hst->bindto);
805
/* handle tcp connection status & register callback the next setp in the process */
806
tcp_connection_state(sd, status, thread_obj, smtp_check_thread, smtp_chk->timeout);