* keepalived-0.3.5 released.
* Rewrite the whole signal handling, registering a terminating
thread on signal.
* Move logsystem to syslog using facility LOG_INFO & LOG_DEBUG.
* Added a daemonization function imported from zebra.
* Rewrite the pidfile handling, check if daemon is running, if not
remove eventual stalled pidfile and create new pidfile.
* Added a strong scheduling framework based on an I/O multiplexer
to handle asynchronous process. This code is imported from zebra
and have been enhanced for keepalived purposes.
Thread types are :
. timeouted read on fd.
. timeouted write on fd.
. timer.
. event.
. terminate event.
=> The zebra framework have been enhanced to add support for timeouted
read/write fds.
=> With this framework keepalived use a Boss/Worker thread model design,
fetching ready thread from a master threading queues.
* Rewrite the configuration file reader to add flexibility on extending.
The dynamic data structure has been rewritten to use apropriate types.
Right now parsing framework is ready for easy new checker structures
integration.
* Rewrite the smtp connector. The implementation take advantage of the
I/O multiplexer. All read/write operations from/to the remote smtp server
are done asynchronously. The implementation is rfc 821 compliant (multiple
receiver are handled by a multiple RCPT TO command as specified in rfc821.3.1).
* Rewrite the IPFW & IPVS wrappers.
* Added support for NAT mask on IP MASQ rules (keyword nat_mask in configuration
file). Added support for sorry server facility, so when all the server from a
VS server pool are removed, a sorry server is automaticaly added to the VS pool
(typically this is used when you have a spare server online).
* Rewrite the previous checkers. Checkers are now based on a hierarchic layer
stack framework. The protocol implemented for the moment is TCP. All layer 5
checkers are using layer4.c primitives with the same design :
. a checker connector thread (creating the socket) registering the connection
checker thread.
. a connection checker thread testing connection states (error, in_progress,
timeout, success). When connection success upper level thread are registered
to handle checks.
* Delay loop is now checkers specifics since we can use a multithreaded framework.
* Update the PDF documentation file.
--- /dev/null
+Alexandre Cassen <acassen@linux-vs.org>
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+\f
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+\f
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+\f
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+\f
+ Appendix: How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+2001-07-15 Alexandre Cassen <acassen@linux-vs.org>
+
+ * keepalived-0.3.5 released.
+ * Rewrite the whole signal handling, registering a terminating
+ thread on signal.
+ * Move logsystem to syslog using facility LOG_INFO & LOG_DEBUG.
+ * Added a daemonization function imported from zebra.
+ * Rewrite the pidfile handling, check if daemon is running, if not
+ remove eventual stalled pidfile and create new pidfile.
+
+ * Added a strong scheduling framework based on an I/O multiplexer
+ to handle asynchronous process. This code is imported from zebra
+ and have been enhanced for keepalived purposes.
+
+ Thread types are :
+ . timeouted read on fd.
+ . timeouted write on fd.
+ . timer.
+ . event.
+ . terminate event.
+
+ => The zebra framework have been enhanced to add support for timeouted
+ read/write fds.
+
+ => With this framework keepalived use a Boss/Worker thread model design,
+ fetching ready thread from a master threading queues.
+
+ * Rewrite the configuration file reader to add flexibility on extending.
+ The dynamic data structure has been rewritten to use apropriate types.
+ Right now parsing framework is ready for easy new checker structures
+ integration.
+
+ * Rewrite the smtp connector. The implementation take advantage of the
+ I/O multiplexer. All read/write operations from/to the remote smtp server
+ are done asynchronously. The implementation is rfc 821 compliant (multiple
+ receiver are handled by a multiple RCPT TO command as specified in rfc821.3.1).
+
+ * Rewrite the IPFW & IPVS wrappers.
+
+ * Added support for NAT mask on IP MASQ rules (keyword nat_mask in configuration
+ file). Added support for sorry server facility, so when all the server from a
+ VS server pool are removed, a sorry server is automaticaly added to the VS pool
+ (typically this is used when you have a spare server online).
+
+ * Rewrite the previous checkers. Checkers are now based on a hierarchic layer
+ stack framework. The protocol implemented for the moment is TCP. All layer 5
+ checkers are using layer4.c primitives with the same design :
+
+ . a checker connector thread (creating the socket) registering the connection
+ checker thread.
+ . a connection checker thread testing connection states (error, in_progress,
+ timeout, success). When connection success upper level thread are registered
+ to handle checks.
+
+ * Delay loop is now checkers specifics since we can use a multithreaded framework.
+
+ * Update the PDF documentation file.
--- /dev/null
+Installation
+============
+
+ 1. uncompress the tarball
+ 2. cd into the directory
+ 3. 'make' and 'make install'. This will install
+ keepalived into your system (binary and configuration file).
+ 4. cd into genhash directory
+ 5. 'make' and 'make install'. This will install
+ the MD5 url digest generator. You need it to configure HTTP GET check.
+ 6. link keepalived.init into your runlevel directory. On redhat systems :
+ ln -s /etc/rc.d/init.d/keepalived.init /etc/rc.d/rc3.d/S99keepalived
+
+Configuration
+=============
+
+ Just take a look to the /etc/keepalived/keepalived.conf file installed.
+ It will give you all the informations needed. If you want more informations
+ considering keepalived, please refer to the keepalived homepage into the
+ documentation section.
+
+ http://keepalived.sourceforge.net
+
+
+Have fun with it !
EXEC= keepalived
CC= gcc
-#CFLAGS= -Wall -Wunused
-CFLAGS=
-DEFS= md5.h iputils.h utils.h pidfile.h cfreader.h icmpcheck.h tcpcheck.h httpget.h smtpwrapper.h ipvswrapper.h libipfwc/libipfwc.h libipfwc/ipfwc_kernel_headers.h ipfwwrapper.h keepalived.h
-OBJECTS= md5.o iputils.o utils.o pidfile.o cfreader.o icmpcheck.o tcpcheck.o httpget.o smtpwrapper.o ipvswrapper.o ipfwwrapper.o libipfwc/libipfwc.a keepalived.o
+
+# To compile with debug messages uncomment the following line
+#CFLAGS= -g -Wall -D DEBUG
+CFLAGS= -g -Wall
+
+DEFS= main.h scheduler.h cfreader.h layer4.h check_tcp.h check_http.h md5.h smtp.h
+OBJECTS= main.o utils.o scheduler.o cfreader.o layer4.o check_tcp.o check_http.o md5.o ipwrapper.o ipvswrapper.o ipfwwrapper.o libipfwc/libipfwc.a pidfile.o smtp.o
INCLUDE= -I/usr/src/linux/include
.c.o:
clean: subclean
rm -f core *.o $(EXEC)
-install:
+install:
install -m 700 keepalived /usr/sbin/
install -m 755 etc/rc.d/init.d/keepalived.init /etc/rc.d/init.d/
mkdir /etc/keepalived
- mkdir /etc/keepalived/log
- touch /etc/keepalived/log/keepalived.log
install -m 644 etc/keepalived/keepalived.conf /etc/keepalived/
+
--- /dev/null
+The main goal of the keepalived project is to add a strong & robust
+keepalive facility to the Linux Virtual Server project.
+It implements a multilayer TCP/IP stack checks. Keepalived implements
+a framework based on three family checks : Layer3, Layer4 & Layer5.
+This framework gives the daemon the ability of checking a LVS server
+pool states. Keepalived can be sumarize as a LVS driving daemon.
+
+Keepalived implementation is based on an I/O multiplexer to handle a
+strong multi-threading framework. All the events process use this I/O
+multiplexer.
+
+Keepalived is free software. See the file COPYING for copying conditions.
* data structure representation the conf file representing
* the loadbalanced server pool.
*
- * Version: $Id: cfreader.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: cfreader.c,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
*
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* Changes:
- * Alexandre Cassen : Initial release
+ * Alexandre Cassen : 2001/06/25 : Initial release
*
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
#include "cfreader.h"
-int AlreadyExist_VS(virtualserver *lstptr, char ip[16], char port[6])
+/* Global keyword structure defs */
+char *string; /* Temp read buffer */
+
+struct keyword keywords[] = {
+ {KW_BEGINFLAG, "{"},
+ {KW_ENDFLAG, "}"},
+
+ {KW_GLOBALDEFS, "global_defs"},
+ {KW_EMAIL, "notification_email"},
+ {KW_EMAILFROM, "notification_email_from"},
+ {KW_LVSID, "lvs_id"},
+ {KW_SMTP, "smtp_server"},
+ {KW_STIMEOUT, "smtp_connect_timeout"},
+
+ {KW_VS, "virtual_server"},
+ {KW_DELAY, "delay_loop"},
+ {KW_LBSCHED, "lb_algo"},
+ {KW_LBKIND, "lb_kind"},
+ {KW_NATMASK, "nat_mask"},
+ {KW_PTIMEOUT, "persistence_timeout"},
+ {KW_PROTOCOL, "protocol"},
+ {KW_SSVR, "sorry_server"},
+
+ {KW_SVR, "real_server"},
+ {KW_WEIGHT, "weight"},
+ {KW_CTIMEOUT, "connect_timeout"},
+ {KW_URL, "url"},
+ {KW_URLPATH, "path"},
+ {KW_DIGEST, "digest"},
+ {KW_NBGETRETRY, "nb_get_retry"},
+ {KW_DELAYRETRY, "delay_before_retry"},
+
+ {KW_ICMPCHECK, "ICMP_CHECK"},
+ {KW_TCPCHECK, "TCP_CHECK"},
+ {KW_HTTPGET, "HTTP_GET"},
+ {KW_SSLGET, "SSL_GET"},
+ {KW_LDAPGET, "LDAP_GET"},
+
+ {KW_UNKNOWN, NULL}
+};
+
+int key(const char *word)
+{
+ int i;
+
+ for (i=0; keywords[i].word; i++)
+ if (strcmp(word, keywords[i].word) == 0)
+ return keywords[i].key;
+
+ return KW_UNKNOWN;
+}
+
+/* Dynamic data structure creation functions start here */
+int already_exist_vs(virtualserver *lstptr, uint32_t ip, uint16_t port)
{
virtualserver *pointerptr=lstptr;
while(lstptr != NULL) {
- if((strcmp(lstptr->addr_ip,ip)==0) && (strcmp(lstptr->addr_port,port)==0)) {
- lstptr=pointerptr;
+ if((lstptr->addr_ip.s_addr == ip) && (lstptr->addr_port == port)) {
+ lstptr = pointerptr;
return 1;
}
- lstptr=(virtualserver *)lstptr->next;
+ lstptr = (virtualserver *)lstptr->next;
}
- lstptr=pointerptr;
+ lstptr = pointerptr;
return 0;
}
-int AlreadyExist_SVR(realserver *lstptr, char ip[16], char port[6])
+int already_exist_svr(realserver *lstptr, uint32_t ip, uint16_t port)
{
realserver *pointerptr=lstptr;
while(lstptr != NULL) {
- if((strcmp(lstptr->addr_ip,ip)==0) && (strcmp(lstptr->addr_port,port)==0)) {
- lstptr=pointerptr;
+ if((lstptr->addr_ip.s_addr == ip) && (lstptr->addr_port == port)) {
+ lstptr = pointerptr;
return 1;
}
- lstptr=(realserver *)lstptr->next;
+ lstptr = (realserver *)lstptr->next;
}
- lstptr=pointerptr;
+ lstptr = pointerptr;
return 0;
}
-notification_email * AddItem_Email(notification_email *lstemail,notification_email *email)
+notification_email * add_item_email(notification_email *lstemail,notification_email *email)
{
notification_email *pointerlst=lstemail;
if (lstemail != NULL) {
- while(lstemail->next != NULL) lstemail=(notification_email *)lstemail->next;
- lstemail->next=(struct notification_email *)email;
+ while(lstemail->next != NULL) lstemail = (notification_email *)lstemail->next;
+ lstemail->next = (struct notification_email *)email;
return pointerlst;
} else {
- lstemail=email;
+ lstemail = email;
return lstemail;
}
}
-virtualserver * AddItem_VS(virtualserver *lstvs,virtualserver *vs)
+virtualserver * add_item_vs(virtualserver *lstvs,virtualserver *vs)
{
virtualserver *pointerlst=lstvs;
- if(AlreadyExist_VS(lstvs,vs->addr_ip,vs->addr_port)) return lstvs;
+ if(already_exist_vs(lstvs, vs->addr_ip.s_addr, vs->addr_port)) return lstvs;
if (lstvs != NULL) {
- while(lstvs->next != NULL) lstvs=(virtualserver *)lstvs->next;
- lstvs->next=(struct virtualserver *)vs;
+ while(lstvs->next != NULL) lstvs = (virtualserver *)lstvs->next;
+ lstvs->next = (struct virtualserver *)vs;
return pointerlst;
} else {
- lstvs=vs;
+ lstvs = vs;
return lstvs;
}
}
-realserver * AddItem_SVR(realserver *lstsvr,realserver *svr)
+realserver * add_item_svr(realserver *lstsvr,realserver *svr)
{
realserver *pointerlst=lstsvr;
- if(AlreadyExist_SVR(lstsvr,svr->addr_ip,svr->addr_port)) return lstsvr;
+ if(already_exist_svr(lstsvr, svr->addr_ip.s_addr, svr->addr_port)) return lstsvr;
if (lstsvr != NULL) {
- while(lstsvr->next != NULL) lstsvr=(realserver *)lstsvr->next;
- lstsvr->next=(struct realserver *)svr;
+ while(lstsvr->next != NULL) lstsvr = (realserver *)lstsvr->next;
+ lstsvr->next = (struct realserver *)svr;
return pointerlst;
} else {
- lstsvr=svr;
+ lstsvr = svr;
return lstsvr;
}
}
-urls * AddItem_Url(urls *lsturls,urls *url)
+urls * add_item_url(urls *lsturls,urls *url)
{
urls *pointerlst=lsturls;
if (lsturls != NULL) {
- while(lsturls->next != NULL) lsturls=(urls *)lsturls->next;
- lsturls->next=(struct urls *)url;
+ while(lsturls->next != NULL) lsturls = (urls *)lsturls->next;
+ lsturls->next = (struct urls *)url;
return pointerlst;
} else {
- lsturls=url;
+ lsturls = url;
return lsturls;
}
}
-urls * RemoveUrl(urls * lstptr)
+/* Dynamic data structure cleanup functions start here */
+urls * remove_url(urls * lstptr)
{
urls *t;
- t=(urls *)lstptr->next;
+ t = (urls *)lstptr->next;
free(lstptr);
return t;
}
-realserver * RemoveSVR(realserver * lstptr)
+realserver * remove_svr(realserver * lstptr)
{
realserver *t;
- t=(realserver *)lstptr->next;
+ t = (realserver *)lstptr->next;
if(lstptr->method->http_get != NULL) {
while(lstptr->method->http_get->check_urls != NULL)
- lstptr->method->http_get->check_urls=RemoveUrl(lstptr->method->http_get->check_urls);
+ lstptr->method->http_get->check_urls = remove_url(lstptr->method->http_get->check_urls);
free(lstptr->method->http_get);
}
- if(lstptr->method->tcp_vanilla != NULL)
- free(lstptr->method->tcp_vanilla);
-
free(lstptr->method);
free(lstptr);
return t;
}
-virtualserver * RemoveVS(virtualserver * lstptr)
+virtualserver * remove_vs(virtualserver * lstptr)
{
virtualserver *t;
- t=(virtualserver *)lstptr->next;
- while(lstptr->svr != NULL) lstptr->svr=RemoveSVR(lstptr->svr);
+ t = (virtualserver *)lstptr->next;
+ while(lstptr->svr != NULL) lstptr->svr = remove_svr(lstptr->svr);
+ free(lstptr->s_svr);
free(lstptr);
return t;
}
-notification_email * RemoveEmail(notification_email *lstptr)
+notification_email * remove_email(notification_email *lstptr)
{
notification_email *t;
- t=(notification_email *)lstptr->next;
+ t = (notification_email *)lstptr->next;
free(lstptr);
return t;
}
-void ClearConf(configuration_data * lstptr)
+void clear_conf(configuration_data * lstptr)
{
while(lstptr->email != NULL)
- lstptr->email=RemoveEmail(lstptr->email);
+ lstptr->email = remove_email(lstptr->email);
while(lstptr->lvstopology != NULL)
- lstptr->lvstopology=RemoveVS(lstptr->lvstopology);
+ lstptr->lvstopology = remove_vs(lstptr->lvstopology);
}
-void PrintConf(configuration_data *lstconf)
+/* Dynamic data structure dump functions start here */
+void dump_httpget(http_get_check *pointerhttpget)
{
- notification_email *pointeremail;
- virtualserver *pointervs;
- realserver *pointersvr;
urls *pointerurls;
- char *tempbuffer;
- tempbuffer=(char *)malloc(TEMPBUFFERLENGTH);
- memset(tempbuffer,0,TEMPBUFFERLENGTH);
+ syslog(LOG_DEBUG," -> Nb get retry = %d",
+ pointerhttpget->nb_get_retry);
+ syslog(LOG_DEBUG," -> Delay before retry = %d",
+ pointerhttpget->delay_before_retry);
+
+ pointerurls = pointerhttpget->check_urls;
+ while(pointerurls != NULL) {
+ syslog(LOG_DEBUG," -> Url = %s, Digest = %s",
+ pointerurls->url,
+ pointerurls->digest);
+
+ pointerurls = (urls *)pointerurls->next;
+ }
+ pointerhttpget->check_urls = pointerurls;
+}
+
+void dump_svr(realserver *pointersvr)
+{
+ while(pointersvr != NULL) {
+ syslog(LOG_DEBUG," -> SVR IP = %s, PORT = %d, WEIGHT = %d",
+ inet_ntoa(pointersvr->addr_ip),
+ ntohs(pointersvr->addr_port),
+ pointersvr->weight);
+
+ switch (pointersvr->method->type) {
+ case ICMP_CHECK_ID:
+ syslog(LOG_DEBUG," -> Keepalive method = ICMP_CHECK");
+ break;
+ case TCP_CHECK_ID:
+ syslog(LOG_DEBUG," -> Keepalive method = TCP_CHECK");
+ syslog(LOG_DEBUG," -> Connection timeout = %d",
+ pointersvr->method->connection_to);
+ break;
+ case HTTP_GET_ID:
+ syslog(LOG_DEBUG," -> Keepalive method = HTTP_GET");
+ syslog(LOG_DEBUG," -> Connection timeout = %d",
+ pointersvr->method->connection_to);
+ dump_httpget(pointersvr->method->http_get);
+ break;
+ case SSL_GET_ID:
+ break;
+ case LDAP_GET_ID:
+ break;
+ }
+
+ pointersvr = (realserver *)pointersvr->next;
+ }
+}
+
+void dump_vs(virtualserver *pointervs)
+{
+ while(pointervs != NULL) {
+ syslog(LOG_DEBUG, " VS IP = %s, PORT = %d",
+ inet_ntoa(pointervs->addr_ip),
+ ntohs(pointervs->addr_port));
+
+ syslog(LOG_DEBUG, " -> delay_loop = %d, lb_algo = %s, "
+ "lb_kind = %s, persistence = %s, protocol = %s",
+ pointervs->delay_loop, pointervs->sched,
+ (pointervs->loadbalancing_kind == 0)?"NAT":"UNKNOWN",
+ pointervs->timeout_persistence,
+ (pointervs->service_type == IPPROTO_TCP)?"TCP":"UDP");
+
+ syslog(LOG_DEBUG, " -> nat mask = %s", inet_ntoa(pointervs->nat_mask));
+
+ if (pointervs->s_svr != NULL) {
+ syslog(LOG_DEBUG, " -> sorry server = [%s:%d]",
+ inet_ntoa(pointervs->s_svr->addr_ip),
+ ntohs(pointervs->s_svr->addr_port));
+ }
+
+ dump_svr(pointervs->svr);
+
+ pointervs = (virtualserver *)pointervs->next;
+ }
+}
+void dump_email(notification_email *pointeremail)
+{
+ while(pointeremail != NULL) {
+ syslog(LOG_DEBUG," Email notification = %s", pointeremail->addr);
+
+ pointeremail = (notification_email *)pointeremail->next;
+ }
+}
+
+void dump_conf(configuration_data *lstconf)
+{
if(lstconf == NULL) {
- logmessage("Empty data configuration !!!\n");
+ syslog(LOG_DEBUG, "Empty data configuration !!!");
} else {
- logmessage("------< Global definitions >------\n");
- memset(tempbuffer,0,TEMPBUFFERLENGTH);
- sprintf(tempbuffer," LVS ID = %s\n",lstconf->lvs_id);
- logmessage(tempbuffer);
- memset(tempbuffer,0,TEMPBUFFERLENGTH);
- sprintf(tempbuffer," Delay loop = %s, Smtp server = %s\n",
- lstconf->delay_loop,lstconf->smtp_server);
- logmessage(tempbuffer);
- memset(tempbuffer,0,TEMPBUFFERLENGTH);
- sprintf(tempbuffer," Email notification from = %s\n",lstconf->email_from);
- logmessage(tempbuffer);
-
- pointeremail=lstconf->email;
- while(lstconf->email != NULL) {
- memset(tempbuffer,0,TEMPBUFFERLENGTH);
- sprintf(tempbuffer," Email notification = %s\n",lstconf->email->addr);
- logmessage(tempbuffer);
-
- lstconf->email=(notification_email *)lstconf->email->next;
+ syslog(LOG_DEBUG,"------< Global definitions >------");
+ syslog(LOG_DEBUG," LVS ID = %s",lstconf->lvs_id);
+ syslog(LOG_DEBUG," Smtp server = %s", inet_ntoa(lstconf->smtp_server));
+ syslog(LOG_DEBUG," Smtp server connection timeout = %d", lstconf->smtp_connection_to);
+ syslog(LOG_DEBUG," Email notification from = %s",lstconf->email_from);
+
+ dump_email(lstconf->email);
+
+ syslog(LOG_DEBUG,"------< LVS Topology >------");
+ dump_vs(lstconf->lvstopology);
+ }
+}
+
+/* Dynamic data structure stream processing functions start here */
+void process_stream_icmpcheck(FILE *stream, realserver *svrfill)
+{
+ keepalive_check *methodfill;
+
+ /* Allocate new method structure */
+ methodfill = (keepalive_check *)malloc(sizeof(keepalive_check));
+ memset(methodfill, 0, sizeof(keepalive_check));
+
+ methodfill->type = ICMP_CHECK_ID;
+ methodfill->http_get = NULL;
+
+ svrfill->method = methodfill;
+}
+
+void process_stream_tcpcheck(FILE *stream, realserver *svrfill)
+{
+ keepalive_check *methodfill;
+
+ /* Allocate new method structure */
+ methodfill = (keepalive_check *)malloc(sizeof(keepalive_check));
+ memset(methodfill, 0, sizeof(keepalive_check));
+
+ methodfill->type = TCP_CHECK_ID;
+ methodfill->http_get = NULL;
+
+ do {
+ switch (key(string)) {
+ case KW_CTIMEOUT:
+ fscanf(stream, "%d", &methodfill->connection_to);
+ break;
+ case KW_UNKNOWN:
+ break;
}
- lstconf->email=pointeremail;
-
- logmessage("------< LVS Topology >------\n");
- pointervs=lstconf->lvstopology;
- while(lstconf->lvstopology != NULL) {
- memset(tempbuffer,0,TEMPBUFFERLENGTH);
- sprintf(tempbuffer," VS IP = %s, PORT = %s\n",lstconf->lvstopology->addr_ip,
- lstconf->lvstopology->addr_port);
- logmessage(tempbuffer);
-
- sprintf(tempbuffer," -> lb_algo = %s, lb_kind = %s, persistence = %s, protocol = %s\n",
- lstconf->lvstopology->sched,lstconf->lvstopology->loadbalancing_kind,
- lstconf->lvstopology->timeout_persistence,lstconf->lvstopology->service_type);
- logmessage(tempbuffer);
-
- pointersvr=lstconf->lvstopology->svr;
- while(lstconf->lvstopology->svr != NULL) {
- sprintf(tempbuffer," -> SVR IP = %s, PORT = %s, WEIGHT = %s\n",
- lstconf->lvstopology->svr->addr_ip,lstconf->lvstopology->svr->addr_port,
- lstconf->lvstopology->svr->weight);
- logmessage(tempbuffer);
-
- /* Displaying ICMP_CHECK resume */
- if (lstconf->lvstopology->svr->method->flag_type == ICMP_CHECK_ID)
- logmessage(" -> Keepalive method = ICMP_CHECK\n");
-
- /* Displaying TCP_CHECK resume */
- if (lstconf->lvstopology->svr->method->flag_type == TCP_CHECK_ID) {
- logmessage(" -> Keepalive method = TCP_CHECK\n");
- sprintf(tempbuffer," -> Connection timeout = %s\n",
- lstconf->lvstopology->svr->method->tcp_vanilla->connection_to);
- logmessage(tempbuffer);
- }
-
- /* Displaying HTTP_GET resume */
- if (lstconf->lvstopology->svr->method->flag_type == HTTP_GET_ID) {
- pointerurls=lstconf->lvstopology->svr->method->http_get->check_urls;
- logmessage(" -> Keepalive method = HTTP_GET\n");
- while (lstconf->lvstopology->svr->method->http_get->check_urls != NULL) {
- sprintf(tempbuffer," -> Url = %s, Digest = %s\n",
- lstconf->lvstopology->svr->method->http_get->check_urls->url,
- lstconf->lvstopology->svr->method->http_get->check_urls->digest);
- logmessage(tempbuffer);
- lstconf->lvstopology->svr->method->http_get->check_urls=(urls *)lstconf->lvstopology->svr->method->http_get->check_urls->next;
- }
- lstconf->lvstopology->svr->method->http_get->check_urls=pointerurls;
-
- sprintf(tempbuffer," -> Connection timeout = %s, Nb get retry = %s\n",
- lstconf->lvstopology->svr->method->http_get->connection_to,
- lstconf->lvstopology->svr->method->http_get->nb_get_retry);
- logmessage(tempbuffer);
- sprintf(tempbuffer," -> Delay before retry = %s\n",
- lstconf->lvstopology->svr->method->http_get->delay_before_retry);
- logmessage(tempbuffer);
- }
-
- lstconf->lvstopology->svr=(realserver *)lstconf->lvstopology->svr->next;
- }
- lstconf->lvstopology->svr=pointersvr;
-
- lstconf->lvstopology=(virtualserver *)lstconf->lvstopology->next;
+ fscanf(stream, "%s", string);
+ } while(key(string) != KW_ENDFLAG);
+
+ svrfill->method = methodfill;
+}
+
+void process_stream_url(FILE *stream, http_get_check *httpgetfill)
+{
+ urls *urlfill;
+
+ /* Allocate new url structure */
+ urlfill = (urls *)malloc(sizeof(urls));
+ memset(urlfill, 0, sizeof(urls));
+
+ urlfill->next = NULL;
+
+ do {
+ switch (key(string)) {
+ case KW_URLPATH:
+ fscanf(stream, "%s", urlfill->url);
+ break;
+ case KW_DIGEST:
+ fscanf(stream, "%s", urlfill->digest);
+ break;
+ case KW_UNKNOWN:
+ break;
}
- lstconf->lvstopology=pointervs;
+ fscanf(stream, "%s", string);
+ } while(key(string) != KW_ENDFLAG);
- }
- free(tempbuffer);
+ httpgetfill->check_urls = add_item_url(httpgetfill->check_urls, urlfill);
}
-configuration_data * ConfReader(configuration_data *conf_data)
+void process_stream_httpget(FILE *stream, realserver *svrfill)
{
- FILE *stream;
- char *string="";
- virtualserver *pointervs;
- virtualserver *vsfill;
- realserver *svrfill;
- notification_email *emailfill;
keepalive_check *methodfill;
http_get_check *httpgetfill;
- urls *urlsfill;
- tcp_vanilla_check *tcpcheckfill;
- stream=fopen(CONFFILE,"r");
- if(stream==NULL) {
- logmessage("ConfReader : Can not read the config file\n");
+ /* Allocate new method structure */
+ methodfill = (keepalive_check *)malloc(sizeof(keepalive_check));
+ memset(methodfill, 0, sizeof(keepalive_check));
+
+ /* Allocate new http get structure */
+ httpgetfill = (http_get_check *)malloc(sizeof(http_get_check));
+ memset(httpgetfill, 0, sizeof(http_get_check));
+
+ methodfill->type = HTTP_GET_ID;
+ methodfill->http_get = httpgetfill;
+ httpgetfill->check_urls = NULL;
+
+ do {
+ switch (key(string)) {
+ case KW_CTIMEOUT:
+ fscanf(stream, "%d", &methodfill->connection_to);
+ break;
+ case KW_NBGETRETRY:
+ fscanf(stream, "%d", &httpgetfill->nb_get_retry);
+ break;
+ case KW_DELAYRETRY:
+ fscanf(stream, "%d", &httpgetfill->delay_before_retry);
+ break;
+ case KW_URL:
+ process_stream_url(stream, httpgetfill);
+ break;
+ case KW_UNKNOWN:
+ break;
+ }
+ fscanf(stream, "%s", string);
+ } while(key(string) != KW_ENDFLAG);
+
+ svrfill->method = methodfill;
+}
+
+void process_stream_svr(FILE *stream, virtualserver *vsfill)
+{
+ realserver *svrfill;
+
+ /* Allocate new real server structure */
+ svrfill = (realserver *)malloc(sizeof(realserver));
+ memset(svrfill, 0, sizeof(realserver));
+
+ /* Add the real server allocated to the virtual server
+ * data structure.
+ */
+ svrfill->next = NULL; /* not required */
+ svrfill->alive = 1; /* server is alive */
+ vsfill->svr = add_item_svr(vsfill->svr, svrfill);
+
+ fscanf(stream, "%s", string);
+ svrfill->addr_ip.s_addr = inet_addr(string);
+ fscanf(stream, "%s", string);
+ svrfill->addr_port = htons(atoi(string));
+
+ do {
+ switch (key(string)) {
+ case KW_WEIGHT:
+ fscanf(stream, "%d", &svrfill->weight);
+ break;
+ case KW_ICMPCHECK:
+ process_stream_icmpcheck(stream, svrfill);
+ break;
+ case KW_TCPCHECK:
+ process_stream_tcpcheck(stream, svrfill);
+ break;
+ case KW_HTTPGET:
+ process_stream_httpget(stream, svrfill);
+ break;
+ case KW_SSLGET: /* not yet implemented */
+ break;
+ case KW_LDAPGET: /* not yet implemented */
+ break;
+ case KW_UNKNOWN:
+ break;
+ }
+ fscanf(stream, "%s", string);
+ } while(key(string) != KW_ENDFLAG);
+}
+
+void process_stream_ssvr(FILE *stream, virtualserver *vsfill)
+{
+ realserver *ssvrfill;
+
+ /* Allocate new sorry server structure */
+ ssvrfill = (realserver *)malloc(sizeof(realserver));
+ memset(ssvrfill, 0, sizeof(realserver));
+
+ /* direct affectation, we can use add_item_svr, so
+ * can specify more than 1 sorry_server...
+ * Not really needed !
+ */
+ vsfill->s_svr = ssvrfill;
+
+ ssvrfill->alive = 0;
+ ssvrfill->weight = 1;
+ ssvrfill->method = NULL;
+ ssvrfill->next = NULL;
+
+ fscanf(stream, "%s", string);
+ ssvrfill->addr_ip.s_addr = inet_addr(string);
+ fscanf(stream, "%s", string);
+ ssvrfill->addr_port = htons(atoi(string));
+}
+
+void process_stream_vs(FILE *stream, configuration_data *conf_data)
+{
+ virtualserver *vsfill;
+
+ /* Allocate new virtual server structure */
+ vsfill = (virtualserver *)malloc(sizeof(virtualserver));
+ memset(vsfill, 0, sizeof(virtualserver));
+
+ /* Add the virtual server allocated to the configuration
+ * data structure.
+ */
+ vsfill->next = NULL; /* not required */
+ vsfill->s_svr = NULL;
+ conf_data->lvstopology = add_item_vs(conf_data->lvstopology, vsfill);
+
+ fscanf(stream, "%s", string);
+ vsfill->addr_ip.s_addr = inet_addr(string);
+ fscanf(stream, "%s", string);
+ vsfill->addr_port = htons(atoi(string));
+
+ do {
+ switch (key(string)) {
+ case KW_DELAY:
+ fscanf(stream, "%d", &vsfill->delay_loop);
+ break;
+ case KW_LBSCHED:
+ fscanf(stream, "%s", vsfill->sched);
+ break;
+ case KW_LBKIND:
+ fscanf(stream, "%s", string);
+ /* For the moment only NAT is supported.
+ * masq_flags : IP_MASQ_F_VS_DROUTE & IP_MASQ_F_VS_TUNNEL not supported.
+ * So we just set masq_flafs to 0.
+ */
+ vsfill->loadbalancing_kind = 0;
+ break;
+ case KW_NATMASK:
+ fscanf(stream, "%s", string);
+ vsfill->nat_mask.s_addr = inet_addr(string);
+ break;
+ case KW_PTIMEOUT:
+ fscanf(stream, "%s", vsfill->timeout_persistence);
+ break;
+ case KW_PROTOCOL:
+ fscanf(stream, "%s", string);
+ vsfill->service_type = (strcmp(string,"TCP") == 0)?IPPROTO_TCP:IPPROTO_UDP;
+ break;
+ case KW_SSVR:
+ process_stream_ssvr(stream, vsfill);
+ break;
+ case KW_SVR:
+ process_stream_svr(stream, vsfill);
+ break;
+ case KW_UNKNOWN:
+ break;
+ }
+ fscanf(stream, "%s", string);
+ } while(key(string) != KW_ENDFLAG);
+}
+
+void process_stream_email(FILE *stream, configuration_data *conf_data)
+{
+ notification_email *emailfill;
+
+ /* Fill in email liste */
+ do {
+ fscanf(stream, "%s", string);
+ if(key(string) != KW_BEGINFLAG && key(string) != KW_ENDFLAG) {
+ emailfill = (notification_email *)malloc(sizeof(notification_email));
+ memset(emailfill, 0, sizeof(notification_email));
+ strncat(emailfill->addr, string, sizeof(emailfill->addr));
+ emailfill->next = NULL;
+ conf_data->email = add_item_email(conf_data->email, emailfill);
+ }
+ } while(key(string) != KW_ENDFLAG);
+}
+
+void process_stream_globaldefs(FILE *stream, configuration_data *conf_data)
+{
+ /* Fill in the global defs structure */
+ do {
+ switch (key(string)) {
+ case KW_LVSID:
+ fscanf(stream, "%s", conf_data->lvs_id);
+ break;
+ case KW_SMTP:
+ fscanf(stream, "%s", string);
+ conf_data->smtp_server.s_addr = inet_addr(string);
+ break;
+ case KW_STIMEOUT:
+ fscanf(stream, "%d", &conf_data->smtp_connection_to);
+ break;
+ case KW_EMAILFROM:
+ fscanf(stream, "%s", conf_data->email_from);
+ break;
+ case KW_EMAIL:
+ process_stream_email(stream, conf_data);
+ break;
+ case KW_UNKNOWN:
+ break;
+ }
+ fscanf(stream, "%s", string);
+ } while(key(string) != KW_ENDFLAG);
+}
+
+configuration_data * conf_reader()
+{
+ configuration_data *conf_data;
+ FILE *stream;
+
+ stream = fopen(CONFFILE, "r");
+ if(!stream) {
+ syslog(LOG_INFO, "ConfReader : Can not read the configuration file...");
return(NULL);
}
- string=(char *)malloc(TEMPBUFFERLENGTH);
- memset(string,0,TEMPBUFFERLENGTH);
- conf_data=(configuration_data *)malloc(sizeof(configuration_data));
- memset(conf_data,0,sizeof(configuration_data));
+ /* Allocate configuration data memory */
+ conf_data = (configuration_data *)malloc(sizeof(configuration_data));
+ memset(conf_data, 0, sizeof(configuration_data));
+
+ /* Allocate temp buffer string */
+ string = (char *)malloc(TEMP_BUFFER_LENGTH);
+ memset(string, 0, TEMP_BUFFER_LENGTH);
/* Initialise the dynamic data structure */
- conf_data->email=NULL;
- conf_data->lvstopology=NULL;
+ conf_data->email = NULL;
+ conf_data->lvstopology = NULL;
while(!feof(stream)) {
- fscanf(stream,"%s",string);
-
- /* Fill in the global defs structure */
- if(strcmp(string,GLOBALDEFS) == 0)
- do {
- if(strcmp(string,DELAY) == 0)
- fscanf(stream,"%s",conf_data->delay_loop);
- if(strcmp(string,SMTP) == 0)
- fscanf(stream,"%s",conf_data->smtp_server);
- if(strcmp(string,EMAILFROM) == 0)
- fscanf(stream,"%s",conf_data->email_from);
- if(strcmp(string,LVSID) == 0)
- fscanf(stream,"%s",conf_data->lvs_id);
- if(strcmp(string,EMAIL) == 0)
- do {
- fscanf(stream,"%s",string);
- if(strcmp(string,BEGINFLAG)!=0 && strcmp(string,ENDFLAG)!=0) {
- emailfill=(notification_email *)malloc(sizeof(notification_email));
- memset(emailfill,0,sizeof(notification_email));
- strncat(emailfill->addr,string,sizeof(emailfill->addr));
- emailfill->next=NULL;
- conf_data->email = AddItem_Email(conf_data->email,emailfill);
- }
- } while(strcmp(string,ENDFLAG) != 0);
- fscanf(stream,"%s",string);
- } while(strcmp(string,ENDFLAG) != 0);
-
- /* Fill in virtual server structure */
- if(strcmp(string,VS) == 0) {
- vsfill=(virtualserver *)malloc(sizeof(virtualserver));
- vsfill->next=NULL;
- conf_data->lvstopology = AddItem_VS(conf_data->lvstopology,vsfill);
-
- pointervs=conf_data->lvstopology;
- while(conf_data->lvstopology->next != NULL)
- conf_data->lvstopology=(virtualserver *)conf_data->lvstopology->next;
-
- fscanf(stream,"%s",vsfill->addr_ip);
- fscanf(stream,"%s",vsfill->addr_port);
- do {
- if(strcmp(string,LBSCHED) == 0)
- fscanf(stream,"%s",vsfill->sched);
- if(strcmp(string,LBKIND) == 0)
- fscanf(stream,"%s",vsfill->loadbalancing_kind);
- if(strcmp(string,PTIMEOUT) == 0)
- fscanf(stream,"%s",vsfill->timeout_persistence);
- if(strcmp(string,PROTOCOL) == 0)
- fscanf(stream,"%s",vsfill->service_type);
-
- /* Fill in real server structure */
- if(strcmp(string,SVR) == 0) {
- svrfill=(realserver *)malloc(sizeof(realserver));
- memset(svrfill,0,sizeof(realserver));
- fscanf(stream,"%s",svrfill->addr_ip);
- fscanf(stream,"%s",svrfill->addr_port);
- svrfill->alive=1;
- do {
- if(strcmp(string,BEGINFLAG)!=0 && strcmp(string,ENDFLAG)!=0) {
- if(strcmp(string,WEIGHT) == 0)
- fscanf(stream,"%s",svrfill->weight);
-
- if(strcmp(string,ICMPCHECK) == 0) {
- methodfill=(keepalive_check *)malloc(sizeof(keepalive_check));
- memset(methodfill,0,sizeof(keepalive_check));
- methodfill->flag_type=ICMP_CHECK_ID;
- methodfill->http_get=NULL;
- methodfill->tcp_vanilla=NULL;
- }
-
- if(strcmp(string,TCPCHECK) == 0) {
- methodfill=(keepalive_check *)malloc(sizeof(keepalive_check));
- memset(methodfill,0,sizeof(keepalive_check));
- methodfill->flag_type=TCP_CHECK_ID;
- tcpcheckfill=(tcp_vanilla_check *)malloc(sizeof(tcp_vanilla_check));
- memset(tcpcheckfill,0,sizeof(tcp_vanilla_check));
- do {
- fscanf(stream,"%s",string);
- if(strcmp(string,BEGINFLAG)!=0 && strcmp(string,ENDFLAG)!=0) {
- if(strcmp(string,CTIMEOUT) == 0)
- fscanf(stream,"%s",tcpcheckfill->connection_to);
- }
- } while (strcmp(string,ENDFLAG) != 0);
- methodfill->http_get=NULL;
- methodfill->tcp_vanilla=tcpcheckfill;
- }
-
- if(strcmp(string,HTTPGET) == 0) {
- methodfill=(keepalive_check *)malloc(sizeof(keepalive_check));
- memset(methodfill,0,sizeof(keepalive_check));
- methodfill->flag_type=HTTP_GET_ID;
- httpgetfill=(http_get_check *)malloc(sizeof(http_get_check));
- memset(httpgetfill,0,sizeof(http_get_check));
- httpgetfill->check_urls=NULL;
- do {
- if(strcmp(string,BEGINFLAG)!=0 && strcmp(string,ENDFLAG)!=0) {
-
- if(strcmp(string,CTIMEOUT) == 0)
- fscanf(stream,"%s",httpgetfill->connection_to);
- if(strcmp(string,NBGETRETRY) == 0)
- fscanf(stream,"%s",httpgetfill->nb_get_retry);
- if(strcmp(string,DELAYRETRY) == 0)
- fscanf(stream,"%s",httpgetfill->delay_before_retry);
-
- if(strcmp(string,URL) == 0) {
- urlsfill=(urls *)malloc(sizeof(urls));
- memset(urlsfill,0,sizeof(urls));
- urlsfill->next=NULL;
- do {
- fscanf(stream,"%s",string);
- if(strcmp(string,BEGINFLAG)!=0 && strcmp(string,ENDFLAG)!=0) {
-
- if(strcmp(string,URLPATH) == 0)
- fscanf(stream,"%s",urlsfill->url);
- if(strcmp(string,DIGEST) == 0)
- fscanf(stream,"%s",urlsfill->digest);
-
- }
- } while (strcmp(string,ENDFLAG) != 0);
- httpgetfill->check_urls=AddItem_Url(httpgetfill->check_urls,urlsfill);
- }
-
- }
- fscanf(stream,"%s",string);
- } while (strcmp(string,ENDFLAG) != 0);
- methodfill->http_get=httpgetfill;
- methodfill->tcp_vanilla=NULL;
- }
- }
- fscanf(stream,"%s",string);
- } while(strcmp(string,ENDFLAG) != 0);
- svrfill->method=methodfill;
- svrfill->next=NULL;
- conf_data->lvstopology->svr = AddItem_SVR(conf_data->lvstopology->svr,svrfill);
- }
-
- fscanf(stream,"%s",string);
- } while(strcmp(string,ENDFLAG) != 0);
- conf_data->lvstopology=pointervs;
+ switch (key(string)) {
+ case KW_GLOBALDEFS:
+ process_stream_globaldefs(stream, conf_data);
+ break;
+ case KW_VS:
+ process_stream_vs(stream, conf_data);
+ break;
+ case KW_UNKNOWN:
+ break;
}
+ fscanf(stream, "%s", string);
}
free(string);
fclose(stream);
-
return(conf_data);
}
*
* Part: cfreader.c include file.
*
- * Version: $Id: cfreader.h,v 0.2.1 2000/12/09 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
+ * Version: $Id: cfreader.h,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#ifndef CFREADER_H
-#define CFREADER_H
-#include <stdio.h>
+#ifndef _CFREADER_H
+#define _CFREADER_H
+
+/* system includes */
#include <stdlib.h>
#include <string.h>
+#include <stdint.h>
+#include <syslog.h>
+#include <arpa/inet.h>
+
+#include <linux/ip_masq.h>
-#define CONFFILE "keepalived.conf"
+/* local includes */
+#include "utils.h"
-#define TEMPBUFFERLENGTH 100
+#define CONFFILE "/etc/keepalived/keepalived.conf"
+
+#define TEMP_BUFFER_LENGTH 100
+#define MAX_EMAIL_LENGTH 45
+#define MAX_LVSID_LENGTH 20
+#define MAX_URL_LENGTH 110
+#define DIGEST_LENGTH 32+1
+#define MAX_TIMEOUT_LENGTH 5
/* Keywords definition */
-#define GLOBALDEFS "global_defs"
-#define VS "virtual_server"
-#define SVR "real_server"
-#define BEGINFLAG "{"
-#define ENDFLAG "}"
-#define DELAY "delay_loop"
-#define EMAIL "notification_email"
-#define EMAILFROM "notification_email_from"
-#define LVSID "lvs_id"
-#define SMTP "smtp_server"
-#define LBSCHED "lb_algo"
-#define LBKIND "lb_kind"
-#define PTIMEOUT "persistence_timeout"
-#define PROTOCOL "protocol"
-#define WEIGHT "weight"
-#define URL "url"
-#define URLPATH "path"
-#define DIGEST "digest"
-#define CTIMEOUT "connect_timeout"
-#define NBGETRETRY "nb_get_retry"
-#define DELAYRETRY "delay_before_retry"
-
-#define ICMPCHECK "ICMP_CHECK"
-#define TCPCHECK "TCP_CHECK"
-#define HTTPGET "HTTP_GET"
-#define SSLGET "SSL_GET"
-
-/* Check method id */
-#define ICMP_CHECK_ID 0x001
-#define TCP_CHECK_ID 0x002
-#define HTTP_GET_ID 0x003
-#define SSL_GET_ID 0x004
+struct keyword {
+ int key;
+ char *word;
+};
+
+/* configuration file keyword definition */
+#define KW_GLOBALDEFS (1 << 0)
+#define KW_VS (1 << 1)
+#define KW_SVR (1 << 2)
+#define KW_SSVR (1 << 3)
+#define KW_BEGINFLAG (1 << 4)
+#define KW_ENDFLAG (1 << 5)
+#define KW_DELAY (1 << 6)
+#define KW_EMAIL (1 << 7)
+#define KW_EMAILFROM (1 << 8)
+#define KW_LVSID (1 << 9)
+#define KW_SMTP (1 << 10)
+#define KW_STIMEOUT (1 << 11)
+#define KW_LBSCHED (1 << 12)
+#define KW_LBKIND (1 << 13)
+#define KW_NATMASK (1 << 14)
+#define KW_PTIMEOUT (1 << 15)
+#define KW_PROTOCOL (1 << 16)
+#define KW_WEIGHT (1 << 17)
+#define KW_URL (1 << 18)
+#define KW_URLPATH (1 << 19)
+#define KW_DIGEST (1 << 20)
+#define KW_CTIMEOUT (1 << 21)
+#define KW_NBGETRETRY (1 << 22)
+#define KW_DELAYRETRY (1 << 23)
+
+#define KW_ICMPCHECK (1 << 24)
+#define KW_TCPCHECK (1 << 25)
+#define KW_HTTPGET (1 << 26)
+#define KW_SSLGET (1 << 27)
+#define KW_LDAPGET (1 << 28)
+
+#define KW_UNKNOWN (1 << 29)
/* Structure definition */
-typedef struct _tcp_vanilla_check {
- char connection_to[4+1];
-} tcp_vanilla_check;
-
typedef struct _urls {
- char url[100+1];
- char digest[32+1];
+ char url[MAX_URL_LENGTH];
+ char digest[DIGEST_LENGTH];
struct urls *next;
} urls;
typedef struct _http_get_check {
- char connection_to[4+1];
- char nb_get_retry[1+1];
- char delay_before_retry[4+1];
+ int nb_get_retry;
+ int delay_before_retry;
urls *check_urls;
} http_get_check;
typedef struct _keepalive_check {
- int flag_type;
- http_get_check *http_get;
- tcp_vanilla_check *tcp_vanilla;
+ int type;
+#define ICMP_CHECK_ID (1 << 0)
+#define TCP_CHECK_ID (1 << 1)
+#define HTTP_GET_ID (1 << 2)
+#define SSL_GET_ID (1 << 3)
+#define LDAP_GET_ID (1 << 4)
+ int connection_to;
+ http_get_check *http_get; /* FIXME : for new checker use union here */
} keepalive_check;
typedef struct _real_server {
- char addr_ip[15+1];
- char addr_port[5+1];
- char weight[3+1];
+ struct in_addr addr_ip;
+ uint16_t addr_port;
+ int weight;
keepalive_check *method;
int alive;
} realserver;
typedef struct _virtual_server {
- char addr_ip[15+1];
- char addr_port[5+1];
- char sched[5+1];
- char loadbalancing_kind[5+1];
- char timeout_persistence[4];
- char service_type[3+1];
+ struct in_addr addr_ip;
+ uint16_t addr_port;
+ uint16_t service_type;
+ int delay_loop;
+ char sched[IP_MASQ_TNAME_MAX];
+ unsigned loadbalancing_kind;
+ struct in_addr nat_mask;
+ char timeout_persistence[MAX_TIMEOUT_LENGTH];
+ realserver *s_svr;
realserver *svr;
struct virtualserver *next;
} virtualserver;
typedef struct _notification_email {
- char addr[40+1];
+ char addr[MAX_EMAIL_LENGTH];
struct notification_email *next;
} notification_email;
typedef struct _configuration_data {
- char delay_loop[4+1];
- char email_from[40+1];
- char smtp_server[15+1];
- char lvs_id[20+1];
+ char lvs_id[MAX_LVSID_LENGTH];
+ char email_from[MAX_EMAIL_LENGTH];
+ struct in_addr smtp_server;
+ int smtp_connection_to;
notification_email *email;
virtualserver *lvstopology;
} configuration_data;
/* prototypes */
-//configuration_data * ConfReader(configuration_data *conf_data);
-//void ClearConf(configuration_data * lstptr);
-//void PrintConf(configuration_data * lstptr);
+extern configuration_data * conf_reader();
+extern void clear_conf(configuration_data * lstptr);
+extern void dump_conf(configuration_data * lstptr);
#endif
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: Checkers arguments structures definitions.
+ *
+ * Version: $Id: check.h,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _CHECK_H
+#define _CHECK_H
+
+/* http specific thread arguments defs */
+struct http_thread_arg {
+ int retry_it; /* current number of get retry */
+ int url_it; /* current url checked index */
+};
+
+/* global thread arguments defs */
+struct thread_arg {
+ configuration_data *root; /* pointer to the configuration root data */
+ virtualserver *vs; /* pointer to the checker thread virtualserver */
+ realserver *svr; /* pointer to the checker thread realserver */
+ void *checker_arg; /* pointer to the specific checker arg */
+};
+
+#endif
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: HTTP GET CHECK. Perform an http get query to a specified
+ * url, compute a MD5 over this result and match it to the
+ * expected value.
+ *
+ * Version: $Id: check_http.c,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * Changes:
+ * Alexandre Cassen : 2001/06/25 : Initial release
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "check_http.h"
+
+/* simple function returning a pointer to the html buffer begin */
+char *extract_html(char *buffer, int size_buffer)
+{
+ char *end=buffer+size_buffer;
+
+ while ( buffer < end &&
+ !(*buffer++ == '\n' &&
+ (*buffer == '\n' || (*buffer ++ == '\r' && *buffer =='\n'))));
+
+ if (*buffer == '\n') return buffer+1;
+ return NULL;
+}
+
+/* return the url pointer of the current url iterator */
+urls *fetch_next_url(struct thread_arg *thread_arg)
+{
+ struct http_thread_arg *checker_arg;
+ int i = 0;
+
+ checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+
+ /* fetch the next url */
+ for (i=0; i<checker_arg->url_it; i++)
+ thread_arg->svr->method->http_get->check_urls=(urls *) thread_arg->svr->method->http_get->check_urls->next;
+
+ if (thread_arg->svr->method->http_get->check_urls != NULL)
+ return thread_arg->svr->method->http_get->check_urls;
+
+ return NULL;
+}
+
+/* read http get result from the remote http server. Apply trigger check to this result */
+int http_response_thread(struct thread *thread)
+{
+ struct thread_arg *thread_arg;
+ struct http_thread_arg *checker_arg;
+ long total_length = 0;
+ int rcv_buffer_size = 0;
+ int di = 0;
+ MD5_CTX context;
+ unsigned char digest[16];
+ char *buffer;
+ char *digest_tmp;
+ char *buffer_html;
+ char *buffer_tmp;
+ urls *fetched_url;
+ urls *pointerurls;
+
+ thread_arg = THREAD_ARG(thread);
+ checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+
+ /* Allocate the get buffers */
+ buffer = (char *)malloc(MAX_BUFFER_LENGTH);
+ buffer_tmp = (char *)malloc(GET_BUFFER_LENGTH);
+
+ /* Cleanup the room */
+ memset(buffer, 0, MAX_BUFFER_LENGTH);
+ memset(buffer_tmp, 0, GET_BUFFER_LENGTH);
+
+ /* Read the fd until remote sever stop sending data.
+ -> FIXME : need to register a new read thread while receiving data */
+ while ((rcv_buffer_size = read(thread->u.fd, buffer_tmp, GET_BUFFER_LENGTH)) != 0) {
+ if (rcv_buffer_size == -1) {
+ if (errno == EAGAIN) goto end;
+ free(buffer);
+ free(buffer_tmp);
+ close(thread->u.fd);
+
+ /* check if server is currently alive */
+ if (thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "DOWN", "=> HTTP CHECK failed on service : cannot receive data <=\n\n");
+ perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
+ }
+
+ /* reset iterator counters */
+ memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
+
+ /* register next timer thread */
+ thread_add_timer(thread->master, http_connect_thread, thread_arg,
+ thread_arg->vs->delay_loop);
+
+ return 0;
+ }
+
+ /* received data overflow buffer size ? */
+ if (total_length >= MAX_BUFFER_LENGTH) {
+ syslog(LOG_INFO, "Received buffer from [%s:%d] overflow our get buffer size.",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+ free(buffer);
+ free(buffer_tmp);
+ close(thread->u.fd);
+
+ /* check if server is currently alive */
+ if (thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "DOWN", "=> HTTP CHECK failed on service : received data overflow <=\n\n");
+ perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
+ }
+
+ /* reset iterator counters */
+ memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
+
+ /* register next timer thread */
+ thread_add_timer(thread->master, http_connect_thread, thread_arg,
+ thread_arg->vs->delay_loop);
+
+ return 0;
+ } else {
+ memcpy(buffer+total_length, buffer_tmp, rcv_buffer_size);
+ memset(buffer_tmp, 0, GET_BUFFER_LENGTH);
+ total_length += rcv_buffer_size;
+ if (rcv_buffer_size < GET_BUFFER_LENGTH) goto end;
+ }
+ }
+
+end:
+
+ buffer_html = extract_html(buffer,total_length);
+
+ if ((total_length-(buffer_html-buffer)) == 0) {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "No html data received from remote server [%s:%d].",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+
+ checker_arg->retry_it++;
+
+ /* The get retry implementation mean that we retry performing
+ * a GET on the same url until the remote web server return
+ * html buffer. This is sometime needed with some applications
+ * servers.
+ */
+ if (checker_arg->retry_it >
+ thread_arg->svr->method->http_get->nb_get_retry) {
+
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Empty buffer returned from [%s:%d] after %d retry.",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port),
+ --checker_arg->retry_it);
+#endif
+
+ /* check if server is currently alive */
+ if (thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "DOWN", "=> HTTP CHECK failed on service : empty buffer received <=\n\n");
+ perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
+ }
+
+ /* reset iterator counters */
+ memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
+
+ /* register next timer thread */
+ thread_add_timer(thread->master, http_connect_thread, thread_arg,
+ thread_arg->vs->delay_loop);
+
+ } else {
+ thread_add_timer(thread->master, http_connect_thread, thread_arg,
+ thread_arg->svr->method->http_get->delay_before_retry);
+ }
+ } else {
+
+ /* Compute MD5SUM */
+ digest_tmp = (char *)malloc(2*sizeof(digest));
+ memset(digest_tmp, 0, 2*sizeof(digest));
+ memset(digest, 0, sizeof(digest));
+ MD5Init(&context);
+ MD5Update(&context, buffer_html, total_length-(buffer_html-buffer));
+ MD5Final(digest, &context);
+
+ for (di=0; di < 16; ++di)
+ sprintf(digest_tmp+2*di, "%02x", digest[di]);
+
+ pointerurls = thread_arg->svr->method->http_get->check_urls;
+ fetched_url = fetch_next_url(thread_arg);
+ thread_arg->svr->method->http_get->check_urls = pointerurls;
+
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "MD5SUM to [%s:%d] url(%d) = [%s].",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port),
+ checker_arg->url_it+1, digest_tmp);
+#endif
+
+ if (strcmp(fetched_url->digest, digest_tmp) != 0) {
+
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "MD5 digest error to [%s:%d] url(%d), expecting MD5SUM [%s].",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port),
+ checker_arg->url_it+1, fetched_url->digest);
+#endif
+
+
+ /* check if server is currently alive */
+ if (thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "DOWN", "=> HTTP CHECK failed on service : MD5 digest mismatch <=\n\n");
+ perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
+ }
+
+ /* reset iterator counters */
+ memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
+
+ /* register next timer thread */
+ thread_add_timer(thread->master, http_connect_thread, thread_arg,
+ thread_arg->vs->delay_loop);
+
+ /* free temporary buffer */
+ free(digest_tmp);
+
+ } else {
+
+ /* reset retry iterator and increment url iterator */
+ checker_arg->retry_it = 0;
+ checker_arg->url_it++;
+ free(digest_tmp);
+
+ thread_add_timer(thread->master, http_connect_thread, thread_arg,
+ thread_arg->svr->method->http_get->delay_before_retry);
+// print_buffer(total_length - (buffer_html - buffer),buffer_html);
+ }
+ }
+
+ free(buffer);
+ free(buffer_tmp);
+ close(thread->u.fd);
+
+ return 1;
+}
+
+/* remote http server is connected, send it the get url query. */
+int http_request_thread(struct thread *thread)
+{
+ struct thread_arg *thread_arg;
+ struct http_thread_arg *checker_arg;
+ char *str_request;
+ urls *fetched_url;
+ urls *pointerurls;
+
+ thread_arg = THREAD_ARG(thread);
+ checker_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+
+ str_request = (char *)malloc(GET_REQUEST_BUFFER_LENGTH);
+ memset(str_request, 0, GET_REQUEST_BUFFER_LENGTH);
+
+ pointerurls = thread_arg->svr->method->http_get->check_urls;
+ fetched_url = fetch_next_url(thread_arg);
+ thread_arg->svr->method->http_get->check_urls = pointerurls;
+
+ if (fetched_url != NULL) {
+ snprintf(str_request, GET_REQUEST_BUFFER_LENGTH, GETCMD, fetched_url->url);
+ } else {
+ /* All the url have been successfully checked.
+ * Check completed.
+ */
+ close(thread->u.fd);
+ free(str_request);
+
+ /* check if server is currently alive */
+ if (!thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "UP", "=> HTTP CHECK succeed on service <=\n\n");
+ perform_svr_state(UP, thread_arg->vs, thread_arg->svr);
+ }
+
+ /* reset iterator counters */
+ memset(checker_arg, 0, sizeof(struct http_thread_arg));
+
+ /* register next timer thread */
+ thread_add_timer(thread->master, http_connect_thread, thread_arg,
+ thread_arg->vs->delay_loop);
+
+ return 1;
+ }
+
+#ifdef DEBUG
+ syslog(LOG_DEBUG,"Processing url(%d) of [%s:%d].",
+ checker_arg->url_it+1,
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+
+ if (send(thread->u.fd, str_request, strlen(str_request), 0) == -1) {
+ syslog(LOG_WARNING, "Cannot send get request to [%s:%d].",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+
+ /* check if server is currently alive */
+ if (thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "DOWN", "=> HTTP CHECK failed on service : cannot send data <=\n\n");
+ perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
+ }
+
+ /* reset iterator counters */
+ memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
+
+ /* register next timer thread */
+ thread_add_timer(thread->master, http_connect_thread, thread_arg,
+ thread_arg->vs->delay_loop);
+
+ close(thread->u.fd);
+ free(str_request);
+ return 0;
+ }
+
+ /* Register read timeouted thread */
+ thread_add_read(thread->master, http_response_thread, thread_arg, thread->u.fd,
+ thread_arg->svr->method->connection_to);
+
+ free(str_request);
+ return 1;
+}
+
+/* HTTP checkers threads */
+int
+http_check_thread(struct thread *thread)
+{
+ struct thread_arg *thread_arg;
+ int status;
+
+ thread_arg = THREAD_ARG(thread);
+
+ status = tcp_socket_state(thread->u.fd, thread, http_check_thread);
+
+ switch (status) {
+ case connect_error:
+#ifdef DEBUG
+ syslog(LOG_DEBUG,"Error connecting HTTP server [%s:%d].",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+
+ /* check if server is currently alive */
+ if (thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "DOWN", "=> HTTP CHECK failed on service : connection error <=\n\n");
+ perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
+ }
+
+ /* reset iterator counters */
+ memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
+
+ /* register next timer thread */
+ thread_add_timer(thread->master, http_connect_thread, thread_arg,
+ thread_arg->vs->delay_loop);
+
+ break;
+
+ case connect_timeout:
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Timeout connecting HTTP server [%s:%d].",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+
+ /* check if server is currently alive */
+ if (thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "DOWN", "=> HTTP CHECK failed on service : connection timeout <=\n\n");
+ perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
+ }
+
+ /* reset iterator counters */
+ memset(thread_arg->checker_arg, 0, sizeof(struct http_thread_arg));
+
+ /* register next timer thread */
+ thread_add_timer(thread->master, http_connect_thread, thread_arg,
+ thread_arg->vs->delay_loop);
+
+ break;
+
+ case connect_success:
+ /* Remote HTTP server is connected.
+ * Register the next step thread http_request_thread.
+ */
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Remote HTTP server [%s:%d] connected.",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+ thread_add_write(thread->master, http_request_thread, thread_arg, thread->u.fd,
+ thread_arg->svr->method->connection_to);
+ break;
+ }
+
+ return 0;
+}
+
+int
+http_connect_thread(struct thread *thread)
+{
+ struct thread_arg *thread_arg;
+ int fd;
+ enum connect_result status;
+
+ thread_arg = THREAD_ARG(thread);
+
+ if ( (fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) {
+#ifdef DEBUG
+ syslog(LOG_DEBUG,"HTTP connect fail to create socket.");
+#endif
+ return 0;
+ }
+
+ status = tcp_connect(fd, thread_arg->svr->addr_ip.s_addr, thread_arg->svr->addr_port);
+
+ /* handle tcp connection status & register check worker thread */
+ tcp_connection_state(fd, status, thread, http_check_thread);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: check_http.c include file.
+ *
+ * Version: $Id: check_http.h,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _HTTP_H
+#define _HTTP_H
+
+/* local includes */
+#include "cfreader.h"
+#include "ipwrapper.h"
+#include "scheduler.h"
+#include "layer4.h"
+#include "md5.h"
+
+/* global defs */
+#define SOCKET_ERROR 0
+#define SOCKET_SUCCESS 1
+
+#define MD5_BUFFER_LENGTH 32
+#define GET_REQUEST_BUFFER_LENGTH 128
+#define GET_BUFFER_LENGTH 2048
+#define MAX_BUFFER_LENGTH 4096
+#define LOGBUFFER_LENGTH 100
+
+/* http get processing command */
+#define GETCMD "GET %s HTTP/1.0\r\n\r\n"
+
+/* Prototypes defs */
+extern int http_connect_thread(struct thread *thread);
+
+extern void smtp_alert(struct thread_master *master,
+ configuration_data *root,
+ realserver *rserver,
+ const char *subject,
+ const char *body);
+
+#endif
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: TCP checker.
+ *
+ * Version: $Id: check_tcp.c,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * Changes:
+ * Alexandre Cassen : 2001/06/25 : Initial release
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "check_tcp.h"
+
+int
+tcp_check_thread(struct thread *thread)
+{
+ struct thread_arg *thread_arg;
+ int status;
+
+ thread_arg = THREAD_ARG(thread);
+
+ status = tcp_socket_state(thread->u.fd, thread, tcp_check_thread);
+
+ /* If status = connect_success, TCP connection to remote host is established.
+ * Otherwise we have a real connection error or connection timeout.
+ */
+ if (status == connect_success) {
+
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "TCP connection to [%s:%d] success.",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+ close(thread->u.fd);
+
+ if (!thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "UP", "=> TCP CHECK succeed on service <=\n\n");
+ perform_svr_state(UP, thread_arg->vs, thread_arg->svr);
+ }
+
+ } else {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "TCP connection to [%s:%d] failed !!!",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+
+ if (thread_arg->svr->alive) {
+ smtp_alert(thread->master, thread_arg->root, thread_arg->svr,
+ "DOWN", "=> TCP CHECK failed on service <=\n\n");
+ perform_svr_state(DOWN, thread_arg->vs, thread_arg->svr);
+ }
+
+ }
+
+ /* Register next timer checker */
+ if (status != connect_in_progress)
+ thread_add_timer(thread->master, tcp_connect_thread, thread_arg,
+ thread_arg->vs->delay_loop);
+
+ return 0;
+}
+
+int
+tcp_connect_thread(struct thread *thread)
+{
+ struct thread_arg *thread_arg;
+ int fd;
+ int status;
+
+ thread_arg = THREAD_ARG(thread);
+
+ if ( (fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "TCP connect fail to create socket.");
+#endif
+ return 0;
+ }
+
+ status = tcp_connect(fd, thread_arg->svr->addr_ip.s_addr, thread_arg->svr->addr_port);
+
+ /* handle tcp connection status & register check worker thread */
+ tcp_connection_state(fd, status, thread, tcp_check_thread);
+
+ return 0;
+}
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: check_tcp.c include file.
+ *
+ * Version: $Id: check_tcp.h,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _TCP_H
+#define _TCP_H
+
+/* system includes */
+#include <unistd.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+/* local includes */
+#include "cfreader.h"
+#include "ipwrapper.h"
+#include "scheduler.h"
+#include "layer4.h"
+#include "smtp.h"
+
+/* Prototypes defs */
+extern int tcp_connect_thread(struct thread *thread);
+
+#endif
# Configuration File for keepalived
-
global_defs {
- delay_loop 60
notification_email {
- acassen@domain.com
- 0633225522@domain.com
+ acassen@firewall.loc
+ failover@firewall.loc
+ sysadmin@firewall.loc
}
- notification_email_from keepalived@domain.com
- smtp_server 192.168.3.62
- lvs_id LVS_MAIN
+ notification_email_from Alexandre.Cassen@firewall.loc
+ smtp_server 192.168.200.1
+ smtp_connect_timeout 30
+ lvs_id LVS_DEVEL
}
virtual_server 10.10.10.2 1358 {
+ delay_loop 6
lb_algo rr
lb_kind NAT
+ nat_mask 255.255.255.0
persistence_timeout 50
protocol TCP
+ sorry_server 192.168.200.200 1358
+
real_server 192.168.200.2 1358 {
weight 1
HTTP_GET {
url {
path /testurl/test.jsp
- digest ec90a42b99ea9a2f5ecbe213ac9eba03
+ digest 640205b7b0fc66c1ea91c463fac6334d
}
url {
path /testurl2/test.jsp
- digest 640205b7b0fc66c1ea91c463fac6334c
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl3/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
}
connect_timeout 3
nb_get_retry 3
- delay_before_retry 2
+ delay_before_retry 3
}
}
+
real_server 192.168.200.3 1358 {
weight 1
HTTP_GET {
path /testurl/test.jsp
digest 640205b7b0fc66c1ea91c463fac6334c
}
+ url {
+ path /testurl2/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334c
+ }
connect_timeout 3
nb_get_retry 3
- delay_before_retry 2
+ delay_before_retry 3
}
}
}
-virtual_server 10.10.10.2 8080 {
- lb_algo rr
+virtual_server 10.10.10.3 1358 {
+ delay_loop 3
+ lb_algo rr
lb_kind NAT
+ nat_mask 255.255.255.0
persistence_timeout 50
protocol TCP
- real_server 192.168.200.4 8080 {
+ real_server 192.168.200.4 1358 {
weight 1
- TCP_CHECK {
+ HTTP_GET {
+ url {
+ path /testurl/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl2/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl3/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
}
}
- real_server 192.168.200.5 8080 {
- weight 1
- ICMP_CHECK
- }
- real_server 192.168.200.6 8080 {
+
+ real_server 192.168.200.5 1358 {
weight 1
- TCP_CHECK {
+ HTTP_GET {
+ url {
+ path /testurl/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl2/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl3/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
}
}
}
-
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: HTTP GET CHECK. Perform an http get query to a specified
- * url, compute a MD5 over this result and match it to the
- * expected value.
- *
- * Version: $Id: httpget.c,v 0.2.1 2000/12/09 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include "httpget.h"
-
-char *extract_html(char *buffer, int size_buffer)
-{
- char *end=buffer+size_buffer;
-
- while ( buffer < end &&
- !(*buffer++ == '\n' &&
- (*buffer == '\n' || (*buffer ++ == '\r' && *buffer =='\n'))));
-
- if (*buffer == '\n') return buffer+1;
- return NULL;
-}
-
-int GET(char *IP_DST, char *PORT_DST, char *URL, char *buffer,int ctimeout)
-{
- register int sdesc;
- int long_inet;
- int rcv_buffer_size=0;
- long total_length=0;
- char *str_request;
- struct hostent *ip_serv;
- struct sockaddr_in adr_serv;
- struct linger li = { 0 };
- char *debugmsg;
- char *buffertmp;
- struct timeval tv;
- fd_set rfds, wfds;
- int rc, flags;
- int arglen;
-
- debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
- buffertmp=(char *)malloc(GET_BUFFER_LENGTH);
- str_request=(char *)malloc(GET_REQUEST_BUFFER_LENGTH);
- memset(buffertmp,0,GET_BUFFER_LENGTH);
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- memset(str_request,0,GET_REQUEST_BUFFER_LENGTH);
-
- sprintf(str_request,GETCMD,URL);
-
- if ( (sdesc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : Can not bind remote address %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- free(str_request);
- free(debugmsg);
- free(buffertmp);
- return(SOCKET_ERROR);
- }
-
- /* free the tcp port after closing the socket descriptor */
- li.l_onoff=1;
- li.l_linger=0;
- setsockopt(sdesc,SOL_SOCKET,SO_LINGER,(char *)&li,sizeof(struct linger));
-
- long_inet = sizeof(struct sockaddr_in);
-
- if ( (ip_serv=gethostbyname(IP_DST)) == NULL) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : Can not resolve remote host %s\n",IP_DST);
- logmessage(debugmsg);
-#endif
- free(str_request);
- free(debugmsg);
- free(buffertmp);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- memset(&adr_serv,0,long_inet);
- adr_serv.sin_family=ip_serv->h_addrtype;
- bcopy(ip_serv->h_addr, &adr_serv.sin_addr.s_addr,ip_serv->h_length);
- adr_serv.sin_port=htons(atoi(PORT_DST));
-
- /* Set read/write socket timeout */
- flags=fcntl(sdesc, F_GETFL);
- fcntl(sdesc, F_SETFL, flags | O_NONBLOCK);
-
- /* Connect the remote host */
- if ( (rc=connect(sdesc, (struct sockaddr *)&adr_serv, long_inet)) == -1) {
- switch (errno) {
- case ETIMEDOUT:
- case EINTR:
- case EHOSTUNREACH:
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : Connection timeout to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- break;
- case ECONNREFUSED:
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : Connection refused to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- break;
- case ENETUNREACH:
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : Network unreachable to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- break;
- case EINPROGRESS: // NONBLOCK socket connection in progress
- goto next;
- default:
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : Network error [%s] to %s:%s\n",strerror(errno),IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- }
-
- free(str_request);
- free(debugmsg);
- free(buffertmp);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
-next:
- /* Timeout settings */
- tv.tv_sec=ctimeout;
- tv.tv_usec=0;
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_SET(sdesc,&rfds);
- FD_SET(sdesc,&wfds);
-
- rc = select(sdesc+1,NULL,&wfds,NULL,&tv);
- if (!FD_ISSET(sdesc,&wfds)) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : Timeout writing data to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- free(str_request);
- free(debugmsg);
- free(buffertmp);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- if (rc < 0) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : Select returned descriptor error to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- free(str_request);
- free(debugmsg);
- free(buffertmp);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- rc = 0;
- arglen=sizeof(int);
- if (getsockopt(sdesc,SOL_SOCKET,SO_ERROR,&rc,&arglen) < 0)
- rc = errno;
-
- if (rc) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : Connection failed to %s:%s (%s)\n",IP_DST,PORT_DST,strerror(rc));
- logmessage(debugmsg);
-#endif
- free(str_request);
- free(debugmsg);
- free(buffertmp);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- /* Sending the http get request */
- if (send(sdesc,str_request,strlen(str_request),0) == -1) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : Can not send data to remote host %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- free(str_request);
- free(debugmsg);
- free(buffertmp);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- /* Proceed the HTTP server reply */
- select(sdesc+1,&rfds,NULL,NULL,&tv);
- if (!FD_ISSET(sdesc,&rfds)) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : Timeout reading data from %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- free(str_request);
- free(buffertmp);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- while((rcv_buffer_size = read(sdesc,buffertmp,GET_BUFFER_LENGTH)) != 0) {
- if ( rcv_buffer_size == -1 ) {
- if(errno == EAGAIN) goto end;
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : Can not recieve data from remote host %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- free(str_request);
- free(debugmsg);
- free(buffertmp);
- close(sdesc);
- return(SOCKET_ERROR);
- }
- memcpy(buffer+total_length,buffertmp,rcv_buffer_size);
- memset(buffertmp,0,GET_BUFFER_LENGTH);
- total_length += rcv_buffer_size;
- }
-
-end:
- close(sdesc);
- free(str_request);
- free(debugmsg);
- free(buffertmp);
- return(total_length);
-}
-
-int HTTP_GET(char *IP_DST,char *PORT_DST,char *URL,char *MDResult,int ctimeout,int getretry,int rdelay)
-{
- char *buffer_http;
- char *buffer_html;
- char *debugmsg;
- md5_state_t state;
- md5_byte_t digest[16];
- int buffer_http_size=0;
- int split_offset=0;
- int nb_retry=0;
- int di;
-
-
- buffer_http=(char *)malloc(GET_BUFFER_LENGTH);
- debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
-
- while (nb_retry < getretry) {
- sleep(rdelay);
- memset(buffer_http,0,GET_BUFFER_LENGTH);
-
- buffer_http_size=GET(IP_DST,PORT_DST,URL,buffer_http,ctimeout);
- buffer_html=extract_html(buffer_http,buffer_http_size);
-
- if (buffer_http_size > 0) {
- if ((buffer_http_size-(buffer_html-buffer_http)) == 0) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : No html buffer received from %s:%s. Retry\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- nb_retry++;
- } else {
- md5_init(&state);
- md5_append(&state, buffer_html,buffer_http_size-(buffer_html-buffer_http));
- md5_finish(&state,digest);
- for (di=0; di < 16; ++di)
- sprintf(MDResult+2*di,"%02x",digest[di]);
- free(debugmsg);
- free(buffer_http);
- return(1);
- }
- } else {
- free(debugmsg);
- free(buffer_http);
- return(0);
- }
- }
-
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"HTTP_GET : No html buffer received from %s:%s after %d retry\n",IP_DST,PORT_DST,getretry);
- logmessage(debugmsg);
-#endif
-
- free(debugmsg);
- free(buffer_http);
- return(0);
-}
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: httpget.c include file.
- *
- * Version: $Id: httpget.h,v 0.2.1 2000/12/09 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef HTTPGET_H
-#define HTTPGET_H
-
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <termios.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/time.h>
-#include <netdb.h>
-#include <net/if.h>
-#include <netinet/in.h>
-#include <netinet/in_systm.h>
-#include <netinet/ip.h>
-#include <netinet/tcp.h>
-#include <netinet/ip_icmp.h>
-#include <linux/if_ether.h>
-#include <string.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#include <errno.h>
-#include "md5.h"
-
-#define SOCKET_ERROR 0
-#define SOCKET_SUCCESS 1
-
-#define GETCMD "GET %s HTTP/1.0\r\n\r\n"
-
-#define MD5_BUFFER_LENGTH 32
-#define GET_REQUEST_BUFFER_LENGTH 128
-#define GET_BUFFER_LENGTH 2048
-#define LOGBUFFER_LENGTH 100
-
-/* prototypes */
-//int HTTP_GET(char *IP_DST,char *PORT_DST,char *URL,char *MDResult,int ctimeout,int getretry,int rdelay);
-
-#endif
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: ICMP CHECK. Build an ICMP packet and send it to a remote
- * server.
- *
- * Version: $Id: icmpcheck.c,v 0.2.3 2001/01/01 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : 2001/01/01 :
- * <+> Added recvfrom_to() function to handle recvfrom timeouted connection.
- * Call this function in ICMP_RCV_ECHOREPLY with 1s timeout.
- * <+> Added a timer (2s timeouted) in ICMP_RCV_ECHOREPLY to check.
- * Check perform on icmp type flag, remote ip address.
- * <+> Added a 3 time ECHO_REQUEST send retry.
- *
- * Alexandre Cassen : 2000/12/09 : Initial release
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include "icmpcheck.h"
-
-int recvfrom_wto(int s, char *buf, int len, struct sockaddr *saddr, int timo)
-{
- int nfound,slen,n;
- struct timeval to;
- fd_set readset,writeset;
-
- to.tv_sec = timo/1000;
- to.tv_usec = 0;
-
- FD_ZERO(&readset);
- FD_ZERO(&writeset);
- FD_SET(s,&readset);
- nfound = select(s+1,&readset,&writeset,NULL,&to);
- if (nfound<0) {
- return(-1);
- }
- if (nfound==0) return -1;
- slen=sizeof(struct sockaddr);
- n=recvfrom(s,buf,len,0,saddr,&slen);
- if (n<0) return -1;
- return n;
-}
-
-int ICMP_SEND_ECHOREQUEST(char *IP_DST)
-{
- struct iphdr *ipHdr;
- struct icmphdr *icmpHdr;
- struct sockaddr_in addr;
- unsigned char *sendbuff;
- char *debugmsg;
- char on = 1;
- int hlen;
- int result;
- int sockfd;
-
- unsigned long tmp;
-
- debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
- sendbuff = (unsigned char *)malloc(BUFFSIZE);
-
- memset(debugmsg,0,BUFFSIZE);
- memset(sendbuff,0,BUFFSIZE);
-
- if((sockfd = socket( AF_INET , SOCK_RAW , IPPROTO_ICMP )) < 0) {
- free(debugmsg);
- free(sendbuff);
- return(SOCKET_ERROR);
- }
-
- if(setsockopt(sockfd , IPPROTO_IP , IP_HDRINCL , &on , sizeof(on)) < 0) {
- free(debugmsg);
- free(sendbuff);
- close(sockfd);
- return(SOCKET_ERROR);
- }
-
- ipHdr = (struct iphdr *)sendbuff;
-
- ipHdr->ihl = 5; /* No options Feild */
- ipHdr->version = 0x4;
- ipHdr->tos = 0 ; /* Low Delay */
- ipHdr->tot_len = sizeof(struct iphdr) + sizeof( struct icmphdr );
- ipHdr->id = htons( getpid() );
- ipHdr->frag_off = 0;
- ipHdr->ttl = 30; /* 30 Hops max */
- ipHdr->protocol = IPPROTO_ICMP;
- ipHdr->check = 0 ;
-
- if( hostToaddr(IP_DST, &tmp) < 0 ) {
- close(sockfd);
- free(sendbuff);
- free(debugmsg);
- return(SOCKET_ERROR);
- }
-
- ipHdr->daddr = tmp;
- ipHdr->check = in_cksum( (unsigned short *)ipHdr , sizeof(struct iphdr) );
- icmpHdr = (struct icmphdr *)( sendbuff + sizeof(struct iphdr) );
- icmpHdr->type = ICMP_ECHO;
- icmpHdr->code = 0;
- icmpHdr->un.echo.id = getpid();
- icmpHdr->un.echo.sequence = getpid();
- icmpHdr->checksum = in_cksum( (unsigned short *)icmpHdr , sizeof(struct icmphdr) );
-
- memset((char *)&addr,0,sizeof(addr));
- addr.sin_addr.s_addr = ipHdr->daddr;
- addr.sin_family = AF_INET;
-
- /* Add the icmp data part
- memcpy(sendbuff+HDRBUFFSIZE,ICMP_DATA,sizeof(ICMP_DATA)); */
-
- if( sendto(sockfd, sendbuff , sizeof(struct iphdr)+sizeof(struct icmphdr) , 0 , (struct sockaddr *)&addr , sizeof(addr)) < 0 ) {
- close(sockfd);
- free(sendbuff);
- free(debugmsg);
- return(SOCKET_ERROR);
- }
-
- close(sockfd);
- free(sendbuff);
- free(debugmsg);
- return(SOCKET_SUCCESS);
-}
-
-int ICMP_RCV_ECHOREPLY(char *IP_DST)
-{
- struct sockaddr_in response_addr ;
- struct iphdr *ip;
- struct icmphdr *icp;
- unsigned char *recvbuff;
- char *debugmsg;
- time_t hint;
- struct tm *date;
- int timer_before, timer_after;
- char on = 1;
- int hlen;
- int result;
- int sockfd;
- int loop=1;
-
- /* Packet pointer affectation */
- debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
- recvbuff=(char *)malloc(BUFFSIZE);
- memset((char *)recvbuff,0,BUFFSIZE);
-
- if((sockfd = socket( AF_INET , SOCK_RAW , IPPROTO_ICMP )) < 0) {
- free(debugmsg);
- free(recvbuff);
- return(SOCKET_ERROR);
- }
-
- if(setsockopt(sockfd , IPPROTO_IP , IP_HDRINCL , &on , sizeof(on)) < 0) {
- free(debugmsg);
- free(recvbuff);
- close(sockfd);
- return(SOCKET_ERROR);
- }
-
- /* Timer initialization */
- /* We can also use a signal SIGALRM and catch this signal with handler to break the loop */
- hint = time((long*)0);
- date = localtime(&hint);
- timer_before = date->tm_sec;
-
- while(loop) {
- result=recvfrom_wto(sockfd,recvbuff,BUFFSIZE,(struct sockaddr *)&response_addr,select_time);
-
-#ifdef DEBUG
- if (result<0) {
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ICMP_CHECK : icmp timeout to [%s]...\n",IP_DST);
- logmessage(debugmsg);
- }
-#endif
-
- ip = (struct iphdr *)recvbuff;
- hlen = ip->ihl << 2;
-
- if (result < hlen+ICMP_MINLEN) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ICMP_CHECK : Received packet too short according to ICMP protocol from [%s]...\n",IP_DST);
- logmessage(debugmsg);
-#endif
- }
-
- icp = (struct icmphdr *)(recvbuff + hlen);
- if ( (icp->type == ICMP_ECHOREPLY) &&
- (ip->saddr == inet_addr(IP_DST)) &&
- (result >= hlen+ICMP_MINLEN) ) {
- close(sockfd);
- free(recvbuff);
- free(debugmsg);
- return(SOCKET_SUCCESS);
- }
-
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ICMP_CHECK : ECHO_REPLY not received from [%s] retry\n",IP_DST);
- logmessage(debugmsg);
-#endif
-
- /* timer to evaluate packet loosed */
- hint = time((long*)0);
- date = localtime(&hint);
- timer_after = date->tm_sec;
-
- if(abs(timer_after-timer_before)>1) loop=0;
- }
-
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ICMP_CHECK : ECHO_REPLY not received from [%s] packet losed\n",IP_DST);
- logmessage(debugmsg);
-#endif
-
- close(sockfd);
- free(recvbuff);
- free(debugmsg);
- return(SOCKET_ERROR);
-}
-
-int ICMP_CHECK(char *IP_DST)
-{
- char *debugmsg;
- int loop=1;
- int retry=0;
-
- /* Memory allocation for the data structures */
- debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
-
- while(loop) {
-
- if(!ICMP_SEND_ECHOREQUEST(IP_DST)) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ICMP_CHECK : Can't send ECHO_REQUEST to [%s]\n",IP_DST);
- logmessage(debugmsg);
-#endif
- free(debugmsg);
- return(SOCKET_ERROR);
- }
- if(ICMP_RCV_ECHOREPLY(IP_DST)) {
- loop=0;
- } else {
- retry++;
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ICMP_CHECK : Reexpedite ECHO_REQUEST to [%s]\n",IP_DST);
- logmessage(debugmsg);
-#endif
- loop=(retry==NB_RETRY)?0:1;
- }
- }
-
- if(retry==NB_RETRY) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ICMP_CHECK : ECHO_REPLY not received from [%s] after 3 try\n",IP_DST);
- logmessage(debugmsg);
-#endif
- free(debugmsg);
- return(SOCKET_ERROR);
- }
-
- free(debugmsg);
- return(SOCKET_SUCCESS);
-}
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: icmpcheck.c include file.
- *
- * Version: $Id: icmpcheck.h,v 0.2.1 2000/12/09 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef ICMPCHECK_H
-#define ICMPCHECK_H
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-
-#define ICMP_DATA "keepalived for LVS"
-
-#define SOCKET_ERROR 0
-#define SOCKET_SUCCESS 1
-
-#define HDRBUFFSIZE (sizeof(struct icmphdr) + sizeof(struct iphdr))
-#define BUFFSIZE (HDRBUFFSIZE + sizeof(ICMP_DATA))
-
-#define DEFAULT_SELECT_TIME 10
-#define ICMP_MINLEN 8
-#define SIZE_ICMP_HDR ICMP_MINLEN
-
-#define DELAY_TIME 1
-#define NB_RETRY 3
-
-#define LOGBUFFER_LENGTH 100
-
-#define select_time (DEFAULT_SELECT_TIME * 100)
-
-/* prototypes */
-//int ICMP_CHECK(char *IP_DST);
-
-#endif
-/*
+/*
* Soft: Keepalived is a failover program for the LVS project
* <www.linuxvirtualserver.org>. It monitor & manipulate
* a loadbalanced server pool using multi-layer checks.
- *
+ *
* Part: IPFW Kernel wrapper. Use Rusty firewall manipulation
* library to add/remove server MASQ rules to the kernel
* firewall framework.
- *
- * Version: $Id: ipfwwrapper.c,v 0.2.7 2001/03/30 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
+ *
+ * Version: $Id: ipfwwrapper.c,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * Changes:
+ * Alexandre Cassen : 2001/06/25 : Initial release
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
#include "ipfwwrapper.h"
-int ipfw_cmd(int cmd, virtualserver *vserver)
+int ipfw_cmd(int cmd, virtualserver *vserver, realserver *rserver)
{
struct ip_fwuser ctl;
- struct in_addr inaddr;
int ret = 1;
- char *debugmsg;
- debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
- memset(&ctl,0,sizeof(struct ip_fwuser));
+ memset(&ctl, 0, sizeof(struct ip_fwuser));
/* Create the firewall MASQ rule */
- strcpy(ctl.label,IP_FW_LABEL_MASQUERADE);
- ctl.ipfw.fw_proto = (strcmp(vserver->service_type,"UDP")==0)?IPPROTO_UDP:IPPROTO_TCP;
- inet_aton(vserver->svr->addr_ip,&ctl.ipfw.fw_src);
- inet_aton(IPFW_SRC_NETMASK,&ctl.ipfw.fw_smsk);
- ctl.ipfw.fw_spts[0] = ctl.ipfw.fw_spts[1] = atoi(vserver->svr->addr_port);
+ strncpy(ctl.label, IP_FW_LABEL_MASQUERADE, IP_FW_MAX_LABEL_LENGTH);
+ ctl.ipfw.fw_proto = vserver->service_type;
+
+ /* compute the source ip address */
+ ctl.ipfw.fw_src.s_addr = rserver->addr_ip.s_addr & vserver->nat_mask.s_addr;
+ ctl.ipfw.fw_smsk.s_addr = vserver->nat_mask.s_addr;
+
+ ctl.ipfw.fw_spts[0] = ctl.ipfw.fw_spts[1] = ntohs(rserver->addr_port);
ctl.ipfw.fw_dpts[0] = 0x0000;
ctl.ipfw.fw_dpts[1] = 0xFFFF;
ctl.ipfw.fw_tosand = 0xFF;
ctl.ipfw.fw_tosxor = 0x00;
- if (cmd&IP_FW_CMD_ADD) {
- ipfwc_delete_entry(IP_FW_LABEL_FORWARD,&ctl);
- if (!(errno&EINVAL)) {
+ if (cmd & IP_FW_CMD_ADD) {
+ ipfwc_delete_entry(IP_FW_LABEL_FORWARD, &ctl);
+ if (!(errno & EINVAL)) {
#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ipfw_cmd : MASQ firewall rule [%s:%s] already exist.\n",
- vserver->svr->addr_ip,vserver->svr->addr_port);
- logmessage(debugmsg);
+ syslog(LOG_DEBUG, "ipfw_cmd : MASQ firewall rule [%s:%d] already exist.",
+ inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port));
#endif
}
- ret &= ipfwc_insert_entry(IP_FW_LABEL_FORWARD,&ctl,1);
+ ret &= ipfwc_insert_entry(IP_FW_LABEL_FORWARD, &ctl, 1);
}
- if (cmd&IP_FW_CMD_DEL) {
- ret &= ipfwc_delete_entry(IP_FW_LABEL_FORWARD,&ctl);
- if (errno&EINVAL) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ipfw_cmd : Can not delete MASQ firewall rule [%s:%s].\n",
- vserver->svr->addr_ip,vserver->svr->addr_port);
- logmessage(debugmsg);
-#endif
- }
- }
+ if (cmd & IP_FW_CMD_DEL)
+ ret &= ipfwc_delete_entry(IP_FW_LABEL_FORWARD, &ctl);
if(!ret) {
#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ipfw_cmd : firewall error (%s) processing [%s:%s] MASQ rule.\n",
- strerror(errno),vserver->svr->addr_ip,vserver->svr->addr_port);
- logmessage(debugmsg);
+ syslog(LOG_DEBUG, "ipfw_cmd : firewall error (%s) processing [%s:%d] MASQ rule.",
+ strerror(errno),
+ inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port));
#endif
- free(debugmsg);
return IPFW_ERROR;
}
- free(debugmsg);
return IPFW_SUCCESS;
}
-
-/*
+/*
* Soft: Keepalived is a failover program for the LVS project
* <www.linuxvirtualserver.org>. It monitor & manipulate
* a loadbalanced server pool using multi-layer checks.
- *
+ *
* Part: ipfwwrapper.c include file.
- *
- * Version: $Id: ipfwwrapper.h,v 0.2.7 2001/03/30 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
+ *
+ * Version: $Id: ipfwwrapper.h,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#ifndef IPFWWRAPPER_H
-#define IPFWWRAPPER_H
+#ifndef _IPFWWRAPPER_H
+#define _IPFWWRAPPER_H
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <netdb.h>
-#include <string.h>
-#include <unistd.h>
+/* system includes */
#include <errno.h>
-#include <ctype.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/param.h>
#include <arpa/inet.h>
+/* locale includes */
#include "libipfwc/libipfwc.h"
#include "cfreader.h"
-#include "ipfwwrappercmd.h"
+/* local defs */
#define IPFW_ERROR 0
#define IPFW_SUCCESS 1
-#define IPFW_SRC_NETMASK "255.255.255.255"
+#define IP_FW_CMD_ADD 0x0001
+#define IP_FW_CMD_DEL 0x0002
-#define LOGBUFFER_LENGTH 100
+/* NAT netmask */
+#define IPFW_SRC_NETMASK 0xffffffff
+
+/* prototypes */
+extern int ipfw_cmd(int cmd, virtualserver *vserver, realserver *rserver);
#endif
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: ipfwwrapper.c include file.
- *
- * Version: $Id: ipfwwrappercmd.h,v 0.2.7 2001/03/30 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef IPFWWRAPPERCMD_H
-#define IPFWWRAPPERCMD_H
-
-/* Cmd codes */
-#define IP_FW_CMD_ADD 0x0001
-#define IP_FW_CMD_DEL 0x0002
-
-/* Return codes */
-#define IPFWNOTDEFINED 0x0003
-#define IPFWSVREXIST 0x0004
-#define IPFWNODEST 0x0005
-
-#endif
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: IP packets Utilities.
- *
- * Version: $Id: iputils.c,v 0.2.1 2000/12/09 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include "iputils.h"
-
-int in_cksum(register unsigned short *ptr , int nbytes)
-{
- register long sum;
- u_short oddbyte;
- register u_short answer;
-
- sum = 0;
- while (nbytes > 1) {
- sum += *ptr++;
- nbytes -= 2;
- }
-
- /* mop up an odd byte, if necessary */
- if (nbytes == 1) {
- oddbyte = 0; /* make sure top half is zero */
- *((u_char *) &oddbyte) = *(u_char *)ptr; /* one byte only */
- sum += oddbyte;
- }
-
- /* Add back carry outs from top 16 bits to low 16 bits. */
- sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */
- sum += (sum >> 16); /* add carry */
- answer = ~sum; /* ones-complement, then truncate to 16 bits */
- return(answer);
-}
-
-int hostToaddr(char *host, u_long *val)
-{
- long in_addr ;
- struct hostent *hp;
-
- if( (in_addr = inet_addr(host)) != -1 ) {
- *val = in_addr;
- return 0;
- } else {
- while( (hp=gethostbyname(host)) == (struct hostent *)0 ) {
- if( h_errno == HOST_NOT_FOUND ) {
- return -1;
- }
- if( h_errno == TRY_AGAIN ) {
- continue;
- }
- if( h_errno == NO_ADDRESS ) {
- return -1;
- }
- }
- bcopy( (const void *)hp->h_addr , (void *)val , hp->h_length );
- return 0;
- }
-}
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: iputils.c include file.
- *
- * Version: $Id: iputils.h,v 0.2.1 2000/12/09 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef IPUTILS_H
-#define IPUTILS_H
-
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/ip_icmp.h>
-
-
-/* prototypes */
-//int in_cksum(register unsigned short *ptr , int nbytes);
-//int hostToaddr(char *host, u_long *val);
-
-
-#endif
* Part: IPVS Kernel wrapper. Use setsockopt call to add/remove
* server to/from the loadbalanced server pool.
*
- * Version: $Id: ipvswrapper.c,v 0.2.7 2001/03/27 $
+ * Version: $Id: ipvswrapper.c,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
*
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* Changes:
* Alexandre Cassen : 2001/03/27 :
- * <+> Added setsockopt return value.
- * <+> Added support to the IP_MASQ_CMD ruleset.
- * IP_MASQ_CMD_ADD : Adding a virtual service.
- * IP_MASQ_CMD_DEL : Deleting a virtual service.
- * IP_MASQ_CMD_ADD_DEST : Adding a real service.
- * IP_MASQ_CMD_DEL_DEST : Deleting a real service.
- *
- * Alexandre Cassen : Initial release
+ * <+> Added setsockopt return value.
+ * <+> Added support to the IP_MASQ_CMD ruleset.
+ * IP_MASQ_CMD_ADD : Adding a virtual service.
+ * IP_MASQ_CMD_DEL : Deleting a virtual service.
+ * IP_MASQ_CMD_ADD_DEST : Adding a real service.
+ * IP_MASQ_CMD_DEL_DEST : Deleting a real service.
+ * Alexandre Cassen : Initial release
*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
*/
#include "ipvswrapper.h"
-int ipvs_cmd(int cmd, virtualserver *vserver)
+int ipvs_cmd(int cmd, virtualserver *vserver, realserver *rserver)
{
struct ip_masq_ctl ctl;
- struct in_addr inaddr;
- char *debugmsg;
int result=0;
int sockfd;
- debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
- memset(&ctl,0, sizeof(struct ip_masq_ctl));
+ memset(&ctl, 0, sizeof(struct ip_masq_ctl));
ctl.m_target = IP_MASQ_TARGET_VS;
ctl.m_cmd = cmd;
- strcpy(ctl.m_tname,vserver->sched);
+ strncpy(ctl.m_tname, vserver->sched, IP_MASQ_TNAME_MAX);
ctl.u.vs_user.weight = -1;
-
- if (strcmp(vserver->loadbalancing_kind,"NAT")==0)
- ctl.u.vs_user.masq_flags = 0;
- else
- if (strcmp(vserver->loadbalancing_kind,"DR")==0)
- ctl.u.vs_user.masq_flags = IP_MASQ_F_VS_DROUTE;
- else
- if (strcmp(vserver->loadbalancing_kind,"TUN")==0)
- ctl.u.vs_user.masq_flags = IP_MASQ_F_VS_TUNNEL;
- else {
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ipvs_pool_cmd : service [%s:%s] [%s] unknown routing method...\n",
- vserver->svr->addr_ip, vserver->svr->addr_port,
- vserver->loadbalancing_kind);
- logmessage(debugmsg);
- logmessage("ipvs_pool_cmd : Check your configuration file...\n");
- free(debugmsg);
- return(IPVS_ERROR);
- }
-
+ ctl.u.vs_user.masq_flags = vserver->loadbalancing_kind;
ctl.u.vs_user.netmask = ((u_int32_t) 0xffffffff); /* f:f:f:f for default netmask */
+ ctl.u.vs_user.protocol = vserver->service_type;
- ctl.u.vs_user.protocol = (strcmp(vserver->service_type,"UDP")==0)?IPPROTO_UDP:IPPROTO_TCP;
-
- if(!parse_timeout(vserver->timeout_persistence,&ctl.u.vs_user.timeout)) {
+ if(!parse_timeout(vserver->timeout_persistence, &ctl.u.vs_user.timeout)) {
#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ipvs_pool_cmd : Virtual service [%s:%s] illegal timeout.\n",
- vserver->addr_ip, vserver->addr_port);
- logmessage(debugmsg);
+ syslog(LOG_DEBUG, "IPVS WRAPPER : Virtual service [%s:%d] illegal timeout.",
+ inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
#endif
}
ctl.u.vs_user.vs_flags = (ctl.u.vs_user.timeout!=0)?IP_VS_SVC_F_PERSISTENT:0;
-
ctl.u.vs_user.vfwmark = 0;
/* VS specific */
- if (inet_aton(vserver->addr_ip,&inaddr) != 0)
- ctl.u.vs_user.vaddr = inaddr.s_addr;
- ctl.u.vs_user.vport = htons(atoi(vserver->addr_port));
+ ctl.u.vs_user.vaddr = vserver->addr_ip.s_addr;
+ ctl.u.vs_user.vport = vserver->addr_port;
/* SVR specific */
if (ctl.m_cmd == IP_MASQ_CMD_ADD_DEST || ctl.m_cmd == IP_MASQ_CMD_DEL_DEST) {
- ctl.u.vs_user.weight = atoi(vserver->svr->weight);
- if (inet_aton(vserver->svr->addr_ip,&inaddr) != 0)
- ctl.u.vs_user.daddr = inaddr.s_addr;
- ctl.u.vs_user.dport = htons(atoi(vserver->svr->addr_port));
+ ctl.u.vs_user.weight = rserver->weight;
+ ctl.u.vs_user.daddr = rserver->addr_ip.s_addr;
+ ctl.u.vs_user.dport = rserver->addr_port;
}
sockfd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
if (sockfd == -1) {
#ifdef DEBUG
- logmessage("ipvs_pool_cmd : Can not initialize SOCK_RAW descriptor\n");
+ syslog(LOG_DEBUG, "IPVS WRAPPER : Can not initialize SOCK_RAW descriptor.");
#endif
- free(debugmsg);
return IPVS_ERROR;
}
if (errno == ESRCH) {
#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ipvs_pool_cmd : Virtual service [%s:%s] not defined.\n",
- vserver->addr_ip, vserver->addr_port);
- logmessage(debugmsg);
+ syslog(LOG_DEBUG, "IPVS WRAPPER : Virtual service [%s:%d] not defined.",
+ inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
#endif
close(sockfd);
- free(debugmsg);
return IPVSNOTDEFINED;
} else if (errno == EEXIST) {
#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ipvs_pool_cmd : Destination already exists [%s:%s]\n",vserver->svr->addr_ip,vserver->svr->addr_port);
- logmessage(debugmsg);
+ syslog(LOG_DEBUG, "IPVS WRAPPER : Destination already exists [%s:%d].",
+ inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port));
#endif
close(sockfd);
- free(debugmsg);
return IPVSSVREXIST;
} else if (errno == ENOENT) {
#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"ipvs_pool_cmd : No such destination [%s:%s]\n",vserver->svr->addr_ip,vserver->svr->addr_port);
- logmessage(debugmsg);
+ syslog(LOG_DEBUG, "IPVS WRAPPER : No such destination [%s:%d].",
+ inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port));
#endif
close(sockfd);
- free(debugmsg);
return IPVSNODEST;
}
close(sockfd);
- free(debugmsg);
return IPVS_SUCCESS;
}
} else
return -1;
}
-
-/*
+/*
* Soft: Keepalived is a failover program for the LVS project
* <www.linuxvirtualserver.org>. It monitor & manipulate
* a loadbalanced server pool using multi-layer checks.
- *
+ *
* Part: ipvswrapper.c include file.
- *
- * Version: $Id: ipvswrapper.h,v 0.2.1 2000/12/09 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
+ *
+ * Version: $Id: ipvswrapper.c,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
-#ifndef IPVSWRAPPER_H
-#define IPVSWRAPPER_H
+#ifndef _IPVSWRAPPER_H
+#define _IPVSWRAPPER_H
-#include <stdio.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <netdb.h>
-#include <string.h>
+/* system includes */
#include <unistd.h>
#include <errno.h>
-#include <ctype.h>
-#include <netinet/in.h>
#include <sys/socket.h>
-#include <sys/types.h>
#include <sys/param.h>
#include <arpa/inet.h>
-
#include <asm/types.h>
+
#include <net/if.h>
#include <netinet/ip_icmp.h>
#include <netinet/udp.h>
#include <net/ip_masq.h>
#include <net/ip_vs.h>
+/* locale includes */
#include "cfreader.h"
#define IPVS_ERROR 0
#define IPVSSVREXIST 0x0004
#define IPVSNODEST 0x0005
-#define LOGBUFFER_LENGTH 100
+/* prototypes */
+extern int parse_timeout(char *buf, unsigned *timeout);
+extern int string_to_number(const char *s, int min, int max);
+extern int ipvs_cmd(int cmd, virtualserver *vserver, realserver *rserver);
#endif
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: Manipulation functions for IPVS & IPFW wrappers.
+ *
+ * Version: $Id: ipwrapper.c,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * Changes:
+ * Alexandre Cassen : 2001/06/25 : Initial release
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "ipwrapper.h"
+
+int clear_service_vs(virtualserver *vserver)
+{
+ realserver *pointersvr;
+
+ pointersvr = vserver->svr;
+ while (vserver->svr) {
+ /* IPVS cleaning server entry */
+ if (!ipvs_cmd(IP_MASQ_CMD_DEL_DEST, vserver, vserver->svr)) {
+ vserver->svr = pointersvr;
+ return 0;
+ }
+
+ /* IPFW cleaning server entry if granularity = /32 */
+ if (vserver->nat_mask.s_addr == HOST_NETMASK)
+ if (!ipfw_cmd(IP_FW_CMD_DEL, vserver, vserver->svr))
+ return 0;
+
+ vserver->svr = (realserver *)vserver->svr->next;
+ }
+ vserver->svr = pointersvr;
+
+ if (!ipvs_cmd(IP_MASQ_CMD_DEL, vserver, vserver->svr))
+ return 0;
+
+ return 1;
+}
+
+int clear_services(virtualserver *vserver)
+{
+ while (vserver) {
+ /* IPVS cleaner processing */
+ if (!clear_service_vs(vserver))
+ return 0;
+
+ /* IPFW cleaner processing */
+ if (vserver->nat_mask.s_addr != HOST_NETMASK) {
+ if (!ipfw_cmd(IP_FW_CMD_DEL, vserver, vserver->svr))
+ return 0;
+ }
+
+ vserver = (virtualserver *)vserver->next;
+ }
+ return 1;
+}
+
+int all_realservers_down(virtualserver *vserver)
+{
+ realserver *pointersvr;
+
+ pointersvr = vserver->svr;
+ while (vserver->svr) {
+ if (vserver->svr->alive) return 0;
+
+ vserver->svr = (realserver *)vserver->svr->next;
+ }
+ vserver->svr = pointersvr;
+ return 1;
+}
+
+void perform_svr_state(int alive, virtualserver *vserver, realserver *rserver)
+{
+ if (!rserver->alive && alive) {
+
+ /* adding a server to the vs pool, if sorry server is flagged alive,
+ * we remove it from the vs pool.
+ */
+ if (vserver->s_svr) {
+ if (vserver->s_svr->alive) {
+ syslog(LOG_INFO, "Removing sorry server [%s:%d] from VS [%s:%d]",
+ inet_ntoa(vserver->s_svr->addr_ip), ntohs(vserver->s_svr->addr_port),
+ inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
+
+ vserver->s_svr->alive = 0;
+ ipvs_cmd(IP_MASQ_CMD_DEL_DEST, vserver, vserver->s_svr);
+ ipfw_cmd(IP_FW_CMD_DEL, vserver, vserver->s_svr);
+ }
+ }
+
+ rserver->alive = alive;
+ syslog(LOG_INFO, "Adding service [%s:%d] to VS [%s:%d]",
+ inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port),
+ inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
+ ipvs_cmd(IP_MASQ_CMD_ADD_DEST, vserver, rserver);
+ if (vserver->nat_mask.s_addr == HOST_NETMASK)
+ ipfw_cmd(IP_FW_CMD_ADD, vserver, rserver);
+
+ } else {
+
+ rserver->alive = alive;
+ syslog(LOG_INFO, "Removing service [%s:%d] from VS [%s:%d]",
+ inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port),
+ inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
+
+ /* server is down, it is removed from the LVS realserver pool */
+ ipvs_cmd(IP_MASQ_CMD_DEL_DEST, vserver, rserver);
+ if (vserver->nat_mask.s_addr == HOST_NETMASK)
+ ipfw_cmd(IP_FW_CMD_DEL, vserver, rserver);
+
+ /* if all the realserver pool is down, we add sorry server */
+ if (vserver->s_svr && all_realservers_down(vserver)) {
+ syslog(LOG_INFO, "Adding sorry server [%s:%d] to VS [%s:%d]",
+ inet_ntoa(vserver->s_svr->addr_ip), ntohs(vserver->s_svr->addr_port),
+ inet_ntoa(vserver->addr_ip), ntohs(vserver->addr_port));
+
+ /* the sorry server is now up in the pool, we flag it alive */
+ vserver->s_svr->alive = 1;
+ ipvs_cmd(IP_MASQ_CMD_ADD_DEST, vserver, vserver->s_svr);
+ ipfw_cmd(IP_FW_CMD_ADD, vserver, vserver->s_svr);
+ }
+
+ }
+}
+
+int init_service_vs(virtualserver *vserver)
+{
+ realserver *pointersvr;
+
+ pointersvr = vserver->svr;
+ while (vserver->svr) {
+ if (!ipvs_cmd(IP_MASQ_CMD_ADD_DEST, vserver, vserver->svr)) {
+ vserver->svr = pointersvr;
+ return 0;
+ }
+
+ /* if we have a /32 mask, we create one nat rules per
+ * realserver.
+ */
+ if (vserver->nat_mask.s_addr == HOST_NETMASK)
+ if(!ipfw_cmd(IP_FW_CMD_ADD, vserver, vserver->svr)) {
+ vserver->svr = pointersvr;
+ return 0;
+ }
+ vserver->svr = (realserver *)vserver->svr->next;
+ }
+ vserver->svr = pointersvr;
+
+ return 1;
+}
+
+int init_services(virtualserver *vserver)
+{
+ virtualserver *pointervs;
+
+ pointervs = vserver;
+ while (vserver) {
+ if (!ipvs_cmd(IP_MASQ_CMD_ADD, vserver, vserver->svr))
+ return 0;
+
+ /* work if all realserver ip address are in the
+ * same network (it is assumed).
+ */
+ if (vserver->nat_mask.s_addr != HOST_NETMASK)
+ if (!ipfw_cmd(IP_FW_CMD_ADD, vserver, vserver->svr))
+ return 0;
+
+ if (!init_service_vs(vserver))
+ return 0;
+
+ vserver = (virtualserver *)vserver->next;
+ }
+ vserver = pointervs;
+
+ return 1;
+}
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: ipwrapper.c include file.
+ *
+ * Version: $Id: ipwrapper.h,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _IPWRAPPER_H
+#define _IPWRAPPER_H
+
+/* system includes */
+#include <syslog.h>
+
+/* locale includes */
+#include "cfreader.h"
+#include "smtp.h"
+
+/* NAT netmask */
+#define HOST_NETMASK 0xffffffff
+
+/* firewall rules framework command */
+#define IP_FW_CMD_ADD 0x0001
+#define IP_FW_CMD_DEL 0x0002
+
+/* UP & DOWN value */
+#define UP 1
+#define DOWN 0
+
+/* prototypes */
+extern void perform_svr_state(int alive, virtualserver *vserver, realserver *rserver);
+extern int init_services(virtualserver *vserver);
+extern int clear_services(virtualserver *vserver);
+
+extern int ipvs_cmd(int cmd, virtualserver *vserver, realserver *rserver);
+extern int ipfw_cmd(int cmd, virtualserver *vserver, realserver *rserver);
+
+#endif
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: Main program structure.
- *
- * Version: $Id: keepalived.c,v 0.2.6 2001/03/01 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : 2001/03/01 :
- * <+> Change the signalhandling.
- * <+> Change the dynamic data structure.
- *
- * Alexandre Cassen : 2000/12/09 : Initial release
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include "keepalived.h"
-
-int main(int argc, char **argv)
-{
- struct sigaction nact, oact;
-
- printf(PROG" v"VERSION"\n");
-
- if (chdir(CONF_HOME_DIR)) {
- fprintf(stderr,"%s: ",CONF_HOME_DIR);
- perror(NULL);
- exit(1);
- }
-
- initdaemonpid(getpid());
- logmessage("Starting keepalived daemon\n");
-
- switch (fork()) {
- case -1:
- perror("fork()");
- exit(3);
- case 0:
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
- if (setsid() == -1) exit(4);
- break;
- default:
- return 0;
- }
-
- initdaemonpid(getpid());
- if(keepalived_running()) {
- logmessage("Keepalived is already running.\n");
- return(0);
- } else
- if(!pidfile_write(getpid()))
- logmessage("Can not write keepalived pidfile.\n");
-
- /* init signal handling */
- sigemptyset(&nact.sa_mask);
- nact.sa_handler = sig_handler;
- nact.sa_flags = SA_RESTART;
- sigaction(SIGALRM,&nact,&oact);
- sigaction(SIGTERM,&nact,&oact);
- sigaction(SIGKILL,&nact,&oact);
- sigaction(SIGSEGV,&nact,&oact);
- sigaction(SIGHUP,&nact,&oact);
- sigaction(SIGINT,&nact,&oact);
-
- if ((lstCONF=(configuration_data *)ConfReader(lstCONF))==NULL) {
- logmessage("Config file contain no data\n");
- exit(0);
- }
-
- logmessage("Using LVS dynamic data representation :\n");
- PrintConf(lstCONF);
-
- if (!init_services(lstCONF->lvstopology)) {
- logmessage("Ending keepalived daemon\n");
- return 0;
- }
-
- while (keep_going) {
- perform_checks(lstCONF);
- sleep(atoi(lstCONF->delay_loop));
- }
-
- pidfile_rm();
- return 0;
-}
-
-void sig_handler(int signum)
-{
- keep_going=0;
- ClearConf(lstCONF);
- logmessage("Ending keepalived daemon\n");
-}
-
-void perform_ipvs(int alive, virtualserver *lstptr)
-{
- char *logbuffer;
-
- logbuffer=(char *)malloc(LOGBUFFER_LENGTH);
- if (!lstptr->svr->alive && alive) {
- lstptr->svr->alive=alive;
- memset(logbuffer,0,LOGBUFFER_LENGTH);
- sprintf(logbuffer,"Adding service [%s:%s] to VS [%s:%s]\n",
- lstptr->svr->addr_ip,lstptr->svr->addr_port,
- lstptr->addr_ip,lstptr->addr_port);
- logmessage(logbuffer);
- ipvs_cmd(IP_MASQ_CMD_ADD_DEST,lstptr);
- ipfw_cmd(IP_FW_CMD_ADD,lstptr);
- } else {
- lstptr->svr->alive=alive;
- memset(logbuffer,0,LOGBUFFER_LENGTH);
- sprintf(logbuffer,"Removing service [%s:%s] from VS [%s:%s]\n",
- lstptr->svr->addr_ip,lstptr->svr->addr_port,
- lstptr->addr_ip,lstptr->addr_port);
- logmessage(logbuffer);
- ipvs_cmd(IP_MASQ_CMD_DEL_DEST,lstptr);
- ipfw_cmd(IP_FW_CMD_DEL,lstptr);
- }
- free(logbuffer);
-}
-
-int init_services(virtualserver *lstptr)
-{
- realserver *pointersvr;
-
- while(lstptr != NULL) {
- if (!ipvs_cmd(IP_MASQ_CMD_ADD,lstptr))
- return 0;
- pointersvr=lstptr->svr;
- while(lstptr->svr != NULL) {
- if (!ipvs_cmd(IP_MASQ_CMD_ADD_DEST,lstptr)) {
- lstptr->svr=pointersvr;
- return 0;
- }
- if(!ipfw_cmd(IP_FW_CMD_ADD,lstptr)) {
- lstptr->svr=pointersvr;
- return 0;
- }
- lstptr->svr=(realserver *)lstptr->svr->next;
- }
- lstptr->svr=pointersvr;
- lstptr=(virtualserver *)lstptr->next;
- }
- return 1;
-}
-
-void perform_checks(configuration_data *lstconf)
-{
- char *MD5Result;
- virtualserver *lstptr;
- realserver *pointersvr;
- urls *pointerurls;
- char *logbuffer;
- int connectionerror;
- int digesterror;
-
- lstptr=lstconf->lvstopology;
-
- logbuffer=(char *)malloc(LOGBUFFER_LENGTH);
- MD5Result=(char *)malloc(16*2*sizeof(char *));
-
- while(lstptr != NULL) {
- pointersvr=lstptr->svr;
- while(lstptr->svr != NULL) {
-
- if (lstptr->svr->method->flag_type == ICMP_CHECK_ID) {
- if (ICMP_CHECK(lstptr->svr->addr_ip)) {
-
- if (!lstptr->svr->alive) {
- memset(logbuffer,0,LOGBUFFER_LENGTH);
- sprintf(logbuffer,"ICMP check succeed to %s.\n",lstptr->svr->addr_ip);
- logmessage(logbuffer);
- perform_ipvs(1,lstptr);
- SMTP_SEND_ALERTES(lstconf,lstptr,"UP","=> ICMP CHECK succeed on service <=\n\n"
- "The service has been added to the server pool\n");
- }
- } else {
- if (lstptr->svr->alive) {
- memset(logbuffer,0,LOGBUFFER_LENGTH);
- sprintf(logbuffer,"ICMP check failed to %s.\n",lstptr->svr->addr_ip);
- logmessage(logbuffer);
- perform_ipvs(0,lstptr);
- SMTP_SEND_ALERTES(lstconf,lstptr,"DOWN","=> ICMP CHECK failed on service <=\n\n"
- "The service has been removed from the server pool\n");
- }
- }
- }
-
- if (lstptr->svr->method->flag_type == TCP_CHECK_ID) {
- if (TCP_CHECK(lstptr->svr->addr_ip,lstptr->svr->addr_port)) {
- if (!lstptr->svr->alive) {
- memset(logbuffer,0,LOGBUFFER_LENGTH);
- sprintf(logbuffer,"TCP check succeed to %s:%s.\n",lstptr->svr->addr_ip,
- lstptr->svr->addr_port);
- logmessage(logbuffer);
- perform_ipvs(1,lstptr);
- SMTP_SEND_ALERTES(lstconf,lstptr,"UP","=> TCP CHECK succeed on service <=\n\n"
- "The service has been added to the server pool\n");
- }
- } else {
- if (lstptr->svr->alive) {
- memset(logbuffer,0,LOGBUFFER_LENGTH);
- sprintf(logbuffer,"TCP check failed to %s:%s.\n",lstptr->svr->addr_ip,
- lstptr->svr->addr_port);
- logmessage(logbuffer);
- perform_ipvs(0,lstptr);
- SMTP_SEND_ALERTES(lstconf,lstptr,"DOWN","=> TCP CHECK failed on service <=\n\n"
- "The service has been removed from the server pool\n");
- }
- }
- }
-
- if (lstptr->svr->method->flag_type == HTTP_GET_ID) {
- connectionerror=0;
- digesterror=0;
-
- /* perform the multi urls md5 check */
- pointerurls=lstptr->svr->method->http_get->check_urls;
- while((lstptr->svr->method->http_get->check_urls != NULL) &&
- !connectionerror && !digesterror) {
- memset(MD5Result,0,16*2*sizeof(char *));
-
- if(!HTTP_GET(lstptr->svr->addr_ip,lstptr->svr->addr_port,
- lstptr->svr->method->http_get->check_urls->url,MD5Result,
- atoi(lstptr->svr->method->http_get->connection_to),
- atoi(lstptr->svr->method->http_get->nb_get_retry),
- atoi(lstptr->svr->method->http_get->delay_before_retry)))
- connectionerror=1;
-
- if (strcmp(lstptr->svr->method->http_get->check_urls->digest,MD5Result) != 0)
- digesterror=1;
-
- lstptr->svr->method->http_get->check_urls=(urls *)lstptr->svr->method->http_get->check_urls->next;
- }
- lstptr->svr->method->http_get->check_urls=pointerurls;
-
- if(!connectionerror) {
-
- if (!digesterror) {
-
- if (!lstptr->svr->alive) {
- memset(logbuffer,0,LOGBUFFER_LENGTH);
- sprintf(logbuffer,"HTTP GET check succeed to %s:%s.\n",lstptr->svr->addr_ip,
- lstptr->svr->addr_port);
- logmessage(logbuffer);
- perform_ipvs(1,lstptr);
- SMTP_SEND_ALERTES(lstconf,lstptr,"UP","=> HTTP GET check succeed on service <=\n\n"
- "The service has been added to the server pool\n");
- }
- } else {
- if (lstptr->svr->alive) {
- memset(logbuffer,0,LOGBUFFER_LENGTH);
- sprintf(logbuffer,"HTTP GET check failed to %s:%s.\n",lstptr->svr->addr_ip,
- lstptr->svr->addr_port);
- logmessage(logbuffer);
- perform_ipvs(0,lstptr);
- SMTP_SEND_ALERTES(lstconf,lstptr,"DOWN","=> HTTP GET check failed on service <=\n\n"
- "The service has been removed from the server pool\n");
- }
- }
- } else {
- if(lstptr->svr->alive) {
- perform_ipvs(0,lstptr);
- SMTP_SEND_ALERTES(lstconf,lstptr,"DOWN","=> HTTP GET check failed on service <=\n\n"
- "The service has been removed from the server pool\n");
- }
- }
-
- }
- lstptr->svr=(realserver *)lstptr->svr->next;
- }
- lstptr->svr=pointersvr;
- lstptr=(virtualserver *)lstptr->next;
- }
- free(MD5Result);
- free(logbuffer);
-}
--- /dev/null
+# Configuration File for keepalived
+
+global_defs {
+ notification_email {
+ acassen
+ }
+ notification_email_from Alexandre.Cassen@firewall.loc
+ smtp_server 192.168.200.1
+ smtp_connect_timeout 30
+ lvs_id LVS_DEVEL
+}
+
+virtual_server 10.10.10.2 1358 {
+ delay_loop 6
+ lb_algo rr
+ lb_kind NAT
+ nat_mask 255.255.255.0
+ persistence_timeout 50
+ protocol TCP
+
+ sorry_server 192.168.200.200 1358
+
+ real_server 192.168.200.2 1358 {
+ weight 1
+ HTTP_GET {
+ url {
+ path /testurl/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl2/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl3/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
+ }
+ }
+
+ real_server 192.168.200.3 1358 {
+ weight 1
+ HTTP_GET {
+ url {
+ path /testurl/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334c
+ }
+ url {
+ path /testurl2/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334c
+ }
+ connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
+ }
+ }
+}
+
+virtual_server 10.10.10.3 1358 {
+ delay_loop 3
+ lb_algo rr
+ lb_kind NAT
+ nat_mask 255.255.255.0
+ persistence_timeout 50
+ protocol TCP
+
+ real_server 192.168.200.4 1358 {
+ weight 1
+ HTTP_GET {
+ url {
+ path /testurl/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl2/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl3/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
+ }
+ }
+
+ real_server 192.168.200.5 1358 {
+ weight 1
+ HTTP_GET {
+ url {
+ path /testurl/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl2/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ url {
+ path /testurl3/test.jsp
+ digest 640205b7b0fc66c1ea91c463fac6334d
+ }
+ connect_timeout 3
+ nb_get_retry 3
+ delay_before_retry 3
+ }
+ }
+}
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: keepalived.c include file.
- *
- * Version: $Id: keepalived.c,v 0.2.1 2000/12/09 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef KEEPALIVED_H
-#define KEEPALIVED_H
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <ctype.h>
-#include <fcntl.h>
-
-#include "cfreader.h"
-#include "smtpwrapper.h"
-#include "icmpcheck.h"
-#include "tcpcheck.h"
-#include "httpget.h"
-#include "utils.h"
-#include "ipvswrapper.h"
-#include "ipfwwrappercmd.h"
-
-#define LOGBUFFER_LENGTH 100
-
-/* Configuration file home directory */
-#define CONF_HOME_DIR "/etc/keepalived/"
-
-/* Sockets connection errors codes */
-#define ERROR_SOCKET 0
-
-/* Global variables */
-volatile sig_atomic_t keep_going = 1;
-configuration_data *lstCONF;
-
-/* Build version */
-#define PROG "keepalived"
-#define VERSION "0.2.7 (03/30, 2001), Alexandre Cassen"
-
-/* prototypes */
-void sig_handler(int signum);
-void perform_checks(configuration_data * lstconf);
-int init_services(virtualserver *lstptr);
-
-#endif
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: Layer4 checkers handling. Register worker threads &
+ * upper layer checkers.
+ *
+ * Version: $Id: layer4.c,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * Changes:
+ * Alexandre Cassen : 2001/06/25 : Initial release
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "layer4.h"
+
+enum connect_result
+tcp_connect (int fd, uint32_t IP_DST, uint16_t PORT_DST)
+{
+ struct linger li = { 0 };
+ int long_inet;
+ struct sockaddr_in adr_serv;
+ int ret;
+ int val;
+
+ /* free the tcp port after closing the socket descriptor */
+ li.l_onoff=1;
+ li.l_linger=0;
+ setsockopt(fd,SOL_SOCKET,SO_LINGER,(char *)&li,sizeof(struct linger));
+
+ long_inet = sizeof(struct sockaddr_in);
+ memset(&adr_serv,0,long_inet);
+ adr_serv.sin_family = AF_INET;
+ adr_serv.sin_port = PORT_DST;
+ adr_serv.sin_addr.s_addr = IP_DST;
+
+ /* Make socket non-block. */
+ val = fcntl (fd, F_GETFL, 0);
+ fcntl (fd, F_SETFL, val|O_NONBLOCK);
+
+ /* Call connect function. */
+ ret = connect (fd, (struct sockaddr *)&adr_serv, long_inet);
+
+ /* Immediate success */
+ if (ret == 0) {
+ fcntl (fd, F_SETFL, val);
+ return connect_success;
+ }
+
+ /* If connect is in progress then return 1 else it's real error. */
+ if (ret < 0) {
+ if (errno != EINPROGRESS)
+ return connect_error;
+ }
+
+ /* restore previous fd args */
+ fcntl (fd, F_SETFL, val);
+ return connect_in_progress;
+}
+
+enum connect_result
+tcp_socket_state(int fd, struct thread *thread,
+ int (*func) (struct thread *))
+{
+ struct thread_arg *thread_arg;
+ int status;
+ int slen;
+ int ret = 0;
+ struct timeval timer_now;
+ struct timeval timer_min;
+
+ thread_arg = THREAD_ARG(thread);
+
+ /* Handle connection timeout */
+ if(thread->type == THREAD_WRITE_TIMEOUT) {
+#ifdef DEBUG
+ if (thread_arg->svr)
+ syslog(LOG_DEBUG, "TCP connection timeout to [%s:%d].",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+ close(thread->u.fd);
+ return connect_timeout;
+ }
+
+ /* Check file descriptor */
+ slen = sizeof(status);
+ if (getsockopt(thread->u.fd, SOL_SOCKET, SO_ERROR, (void *)&status, &slen) < 0)
+ ret = errno;
+
+ /* Connection failed !!! */
+ if (ret) {
+#ifdef DEBUG
+ if (thread_arg->svr)
+ syslog(LOG_DEBUG, "TCP connection failed to [%s:%d].",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+ close(thread->u.fd);
+ return connect_error;
+ }
+
+ /* If status = 0, TCP connection to remote host is established.
+ * Otherwise register checker thread to handle connection in progress,
+ * and other error code until connection is established.
+ * Recompute the write timeout (or pending connection).
+ */
+ if (status != 0) {
+#ifdef DEBUG
+ if (thread_arg->svr)
+ syslog(LOG_DEBUG, "TCP connection to [%s:%d] still IN_PROGRESS.",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+
+ gettimeofday(&timer_now,NULL);
+ timer_min = thread_timer_sub(thread->sands,timer_now);
+
+ if (timer_min.tv_sec <= 0)
+ thread_add_write(thread->master, func,
+ thread_arg, thread->u.fd, 0);
+ else
+ thread_add_write(thread->master, func,
+ thread_arg, thread->u.fd, timer_min.tv_sec);
+
+ return connect_in_progress;
+ }
+
+ return connect_success;
+}
+
+void
+tcp_connection_state(int fd, enum connect_result status,
+ struct thread *thread,
+ int (*func) (struct thread *))
+{
+ struct thread_arg *thread_arg;
+
+ thread_arg = THREAD_ARG(thread);
+
+ switch (status) {
+ case connect_error:
+#ifdef DEBUG
+ syslog(LOG_DEBUG,"TCP connection ERROR to [%s:%d].",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+ close(fd);
+ break;
+
+ case connect_success:
+#ifdef DEBUG
+ syslog(LOG_DEBUG,"TCP connection SUCCESS to [%s:%d].",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+ thread_add_write(thread->master, func, thread_arg, fd,
+ thread_arg->svr->method->connection_to);
+ break;
+
+ /* Checking non-blocking connect, we wait until socket is writable */
+ case connect_in_progress:
+#ifdef DEBUG
+ syslog(LOG_DEBUG,"TCP connection to [%s:%d] now IN_PROGRESS.",
+ inet_ntoa(thread_arg->svr->addr_ip),
+ ntohs(thread_arg->svr->addr_port));
+#endif
+ thread_add_write(thread->master, func, thread_arg, fd,
+ thread_arg->svr->method->connection_to);
+ break;
+
+ default:
+ break;
+ }
+}
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: layer4.c include file.
+ *
+ * Version: $Id: layer4.h,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _LAYER4_H
+#define _LAYER4_H
+
+/* system includes */
+#include <unistd.h>
+#include <stdint.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+
+/* local includes */
+#include "cfreader.h"
+#include "scheduler.h"
+#include "check_http.h"
+
+enum connect_result {
+ connect_error,
+ connect_success,
+ connect_in_progress,
+ connect_timeout
+};
+
+/* Prototypes defs */
+extern enum connect_result
+tcp_connect(int fd, uint32_t IP_DST, uint16_t PORT_DST);
+
+extern enum connect_result
+tcp_socket_state(int fd, struct thread *thread,
+ int (*func) (struct thread *));
+
+extern void
+tcp_connection_state(int fd, enum connect_result status,
+ struct thread *thread,
+ int (*func) (struct thread *));
+
+#endif
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: Main program structure.
+ *
+ * Version: $Id: main.c,v 0.3.3 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * Changes:
+ * Alexandre Cassen : 2001/06/25 : Rewritte the whole framework
+ * <+> Added scheduling framework using I/O multiplexer thread
+ * <+> Added syslog support
+ * <+> Change the signal handling
+ * Alexandre Cassen : 2000/12/09 : Initial release
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "main.h"
+
+/* SIGHUP handler */
+void sighup(int sig)
+{
+ syslog(LOG_INFO, "Terminating on signal");
+
+ /* register the terminate thread */
+ thread_add_terminate_event(master);
+}
+
+/* Signal wrapper */
+void * signal_set(int signo, void (*func)(int))
+{
+ int ret;
+ struct sigaction sig;
+ struct sigaction osig;
+
+ sig.sa_handler = func;
+ sigemptyset (&sig.sa_mask);
+ sig.sa_flags = 0;
+#ifdef SA_RESTART
+ sig.sa_flags |= SA_RESTART;
+#endif /* SA_RESTART */
+
+ ret = sigaction (signo, &sig, &osig);
+
+ if (ret < 0)
+ return (SIG_ERR);
+ else
+ return (osig.sa_handler);
+}
+
+/* Initialize signal handler */
+void signal_init()
+{
+ signal_set (SIGHUP, sighup);
+ signal_set (SIGINT, sighup);
+ signal_set (SIGTERM, sighup);
+ signal_set (SIGKILL, sighup);
+}
+
+/* Daemonization function coming from zebra source code */
+int daemon (int nochdir, int noclose)
+{
+ pid_t pid;
+
+ pid = fork ();
+
+ /* In case of fork is error. */
+ if (pid < 0)
+ {
+ perror ("fork");
+ return -1;
+ }
+
+ /* In case of this is parent process. */
+ if (pid != 0)
+ exit (0);
+
+ /* Become session leader and get pid. */
+ pid = setsid();
+
+ if (pid < -1)
+ {
+ perror ("setsid");
+ return -1;
+ }
+
+ /* Change directory to root. */
+ if (! nochdir)
+ chdir ("/");
+
+ /* File descriptor close. */
+ if (! noclose)
+ {
+ int fd;
+
+ fd = open ("/dev/null", O_RDWR, 0);
+ if (fd != -1)
+ {
+ dup2 (fd, STDIN_FILENO);
+ dup2 (fd, STDOUT_FILENO);
+ dup2 (fd, STDERR_FILENO);
+ if (fd > 2)
+ close (fd);
+ }
+ }
+
+ umask (0);
+
+ return 0;
+}
+
+/* Entry point */
+int main(int argc, char **argv)
+{
+ configuration_data *conf_data;
+ struct thread thread;
+
+ openlog(PROG,LOG_PID, LOG_DAEMON);
+ syslog(LOG_INFO, "Starting "PROG" v"VERSION);
+
+ /* Check if keepalived is already running */
+ if (keepalived_running()) {
+ syslog(LOG_INFO, "Stopping "PROG" v"VERSION);
+ closelog();
+ exit(0);
+ }
+ /* write the pidfile */
+ if (!pidfile_write(getpid())) {
+ syslog(LOG_INFO, "Stopping "PROG" v"VERSION);
+ closelog();
+ exit(0);
+ }
+
+ /* Parse the configuration file */
+ if (!(conf_data = (configuration_data *)conf_reader())) {
+ closelog();
+ exit(0);
+ }
+
+#ifdef DEBUG
+ dump_conf(conf_data);
+#endif
+
+ if (!init_services(conf_data->lvstopology)) {
+ syslog(LOG_INFO, "Stopping "PROG" v"VERSION);
+ closelog();
+ clear_conf(conf_data);
+ exit(0);
+ }
+
+ /* Signal handling initialization */
+ signal_init();
+
+ /* daemonize process */
+ daemon(0, 0);
+
+ /* Create the master thread */
+ master = thread_make_master();
+
+ /* registering worker threads */
+ register_worker_thread(master, conf_data);
+
+ /* processing the master thread queues, return and execute one ready thread */
+ while(thread_fetch(master, &thread))
+ thread_call(&thread);
+
+ /* Reached when terminate signal catched */
+ syslog(LOG_INFO, "Stopping "PROG" v"VERSION);
+
+ /* We then cleanup the room & closelog */
+ thread_destroy_master(master);
+ clear_services(conf_data->lvstopology);
+ clear_conf(conf_data);
+ closelog();
+ pidfile_rm();
+
+ /* finally return from system */
+ exit(0);
+}
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: Main program include file.
+ *
+ * Version: $Id: main.h,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _MAIN_H
+#define _MAIN_H
+
+/* global includes */
+#include <sys/stat.h>
+
+/* local includes */
+#include "utils.h"
+#include "pidfile.h"
+#include "cfreader.h"
+#include "scheduler.h"
+#include "ipwrapper.h"
+#include "smtp.h"
+
+/* global var */
+struct thread_master *master;
+
+/* Build version */
+#define PROG "keepalived"
+#define VERSION "0.3.5 (13/07, 2001)"
+
+#endif
-/*\r
- Copyright (C) 1999 Aladdin Enterprises. All rights reserved.\r
-\r
- This software is provided 'as-is', without any express or implied\r
- warranty. In no event will the authors be held liable for any damages\r
- arising from the use of this software.\r
-\r
- Permission is granted to anyone to use this software for any purpose,\r
- including commercial applications, and to alter it and redistribute it\r
- freely, subject to the following restrictions:\r
-\r
- 1. The origin of this software must not be misrepresented; you must not\r
- claim that you wrote the original software. If you use this software\r
- in a product, an acknowledgment in the product documentation would be\r
- appreciated but is not required.\r
- 2. Altered source versions must be plainly marked as such, and must not be\r
- misrepresented as being the original software.\r
- 3. This notice may not be removed or altered from any source distribution.\r
-\r
- L. Peter Deutsch\r
- ghost@aladdin.com\r
-\r
- */\r
-/*$Id: md5.c $ */\r
-/*\r
- Independent implementation of MD5 (RFC 1321).\r
-\r
- This code implements the MD5 Algorithm defined in RFC 1321.\r
- It is derived directly from the text of the RFC and not from the\r
- reference implementation.\r
-\r
- The original and principal author of md5.c is L. Peter Deutsch\r
- <ghost@aladdin.com>. Other authors are noted in the change history\r
- that follows (in reverse chronological order):\r
-\r
- 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.\r
- 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5).\r
- 1999-05-03 lpd Original version.\r
- */\r
-\r
-#include "md5.h"\r
-\r
-#define T1 0xd76aa478\r
-#define T2 0xe8c7b756\r
-#define T3 0x242070db\r
-#define T4 0xc1bdceee\r
-#define T5 0xf57c0faf\r
-#define T6 0x4787c62a\r
-#define T7 0xa8304613\r
-#define T8 0xfd469501\r
-#define T9 0x698098d8\r
-#define T10 0x8b44f7af\r
-#define T11 0xffff5bb1\r
-#define T12 0x895cd7be\r
-#define T13 0x6b901122\r
-#define T14 0xfd987193\r
-#define T15 0xa679438e\r
-#define T16 0x49b40821\r
-#define T17 0xf61e2562\r
-#define T18 0xc040b340\r
-#define T19 0x265e5a51\r
-#define T20 0xe9b6c7aa\r
-#define T21 0xd62f105d\r
-#define T22 0x02441453\r
-#define T23 0xd8a1e681\r
-#define T24 0xe7d3fbc8\r
-#define T25 0x21e1cde6\r
-#define T26 0xc33707d6\r
-#define T27 0xf4d50d87\r
-#define T28 0x455a14ed\r
-#define T29 0xa9e3e905\r
-#define T30 0xfcefa3f8\r
-#define T31 0x676f02d9\r
-#define T32 0x8d2a4c8a\r
-#define T33 0xfffa3942\r
-#define T34 0x8771f681\r
-#define T35 0x6d9d6122\r
-#define T36 0xfde5380c\r
-#define T37 0xa4beea44\r
-#define T38 0x4bdecfa9\r
-#define T39 0xf6bb4b60\r
-#define T40 0xbebfbc70\r
-#define T41 0x289b7ec6\r
-#define T42 0xeaa127fa\r
-#define T43 0xd4ef3085\r
-#define T44 0x04881d05\r
-#define T45 0xd9d4d039\r
-#define T46 0xe6db99e5\r
-#define T47 0x1fa27cf8\r
-#define T48 0xc4ac5665\r
-#define T49 0xf4292244\r
-#define T50 0x432aff97\r
-#define T51 0xab9423a7\r
-#define T52 0xfc93a039\r
-#define T53 0x655b59c3\r
-#define T54 0x8f0ccc92\r
-#define T55 0xffeff47d\r
-#define T56 0x85845dd1\r
-#define T57 0x6fa87e4f\r
-#define T58 0xfe2ce6e0\r
-#define T59 0xa3014314\r
-#define T60 0x4e0811a1\r
-#define T61 0xf7537e82\r
-#define T62 0xbd3af235\r
-#define T63 0x2ad7d2bb\r
-#define T64 0xeb86d391\r
-\r
-static void\r
-md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/)\r
-{\r
- md5_word_t\r
- a = pms->abcd[0], b = pms->abcd[1],\r
- c = pms->abcd[2], d = pms->abcd[3];\r
- md5_word_t t;\r
-\r
-#ifndef ARCH_IS_BIG_ENDIAN\r
-# define ARCH_IS_BIG_ENDIAN 1 /* slower, default implementation */\r
-#endif\r
-#if ARCH_IS_BIG_ENDIAN\r
-\r
- /*\r
- * On big-endian machines, we must arrange the bytes in the right\r
- * order. (This also works on machines of unknown byte order.)\r
- */\r
- md5_word_t X[16];\r
- const md5_byte_t *xp = data;\r
- int i;\r
-\r
- for (i = 0; i < 16; ++i, xp += 4)\r
- X[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24);\r
-\r
-#else /* !ARCH_IS_BIG_ENDIAN */\r
-\r
- /*\r
- * On little-endian machines, we can process properly aligned data\r
- * without copying it.\r
- */\r
- md5_word_t xbuf[16];\r
- const md5_word_t *X;\r
-\r
- if (!((data - (const md5_byte_t *)0) & 3)) {\r
- /* data are properly aligned */\r
- X = (const md5_word_t *)data;\r
- } else {\r
- /* not aligned */\r
- memcpy(xbuf, data, 64);\r
- X = xbuf;\r
- }\r
-#endif\r
-\r
-#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n))))\r
-\r
- /* Round 1. */\r
- /* Let [abcd k s i] denote the operation\r
- a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */\r
-#define F(x, y, z) (((x) & (y)) | (~(x) & (z)))\r
-#define SET(a, b, c, d, k, s, Ti) t = a + F(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b\r
- /* Do the following 16 operations. */\r
- SET(a, b, c, d, 0, 7, T1);\r
- SET(d, a, b, c, 1, 12, T2);\r
- SET(c, d, a, b, 2, 17, T3);\r
- SET(b, c, d, a, 3, 22, T4);\r
- SET(a, b, c, d, 4, 7, T5);\r
- SET(d, a, b, c, 5, 12, T6);\r
- SET(c, d, a, b, 6, 17, T7);\r
- SET(b, c, d, a, 7, 22, T8);\r
- SET(a, b, c, d, 8, 7, T9);\r
- SET(d, a, b, c, 9, 12, T10);\r
- SET(c, d, a, b, 10, 17, T11);\r
- SET(b, c, d, a, 11, 22, T12);\r
- SET(a, b, c, d, 12, 7, T13);\r
- SET(d, a, b, c, 13, 12, T14);\r
- SET(c, d, a, b, 14, 17, T15);\r
- SET(b, c, d, a, 15, 22, T16);\r
-#undef SET\r
-\r
- /* Round 2. */\r
- /* Let [abcd k s i] denote the operation\r
- a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */\r
-#define G(x, y, z) (((x) & (z)) | ((y) & ~(z)))\r
-#define SET(a, b, c, d, k, s, Ti) t = a + G(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b\r
- /* Do the following 16 operations. */\r
- SET(a, b, c, d, 1, 5, T17);\r
- SET(d, a, b, c, 6, 9, T18);\r
- SET(c, d, a, b, 11, 14, T19);\r
- SET(b, c, d, a, 0, 20, T20);\r
- SET(a, b, c, d, 5, 5, T21);\r
- SET(d, a, b, c, 10, 9, T22);\r
- SET(c, d, a, b, 15, 14, T23);\r
- SET(b, c, d, a, 4, 20, T24);\r
- SET(a, b, c, d, 9, 5, T25);\r
- SET(d, a, b, c, 14, 9, T26);\r
- SET(c, d, a, b, 3, 14, T27);\r
- SET(b, c, d, a, 8, 20, T28);\r
- SET(a, b, c, d, 13, 5, T29);\r
- SET(d, a, b, c, 2, 9, T30);\r
- SET(c, d, a, b, 7, 14, T31);\r
- SET(b, c, d, a, 12, 20, T32);\r
-#undef SET\r
-\r
- /* Round 3. */\r
- /* Let [abcd k s t] denote the operation\r
- a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */\r
-#define H(x, y, z) ((x) ^ (y) ^ (z))\r
-#define SET(a, b, c, d, k, s, Ti) t = a + H(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b\r
- /* Do the following 16 operations. */\r
- SET(a, b, c, d, 5, 4, T33);\r
- SET(d, a, b, c, 8, 11, T34);\r
- SET(c, d, a, b, 11, 16, T35);\r
- SET(b, c, d, a, 14, 23, T36);\r
- SET(a, b, c, d, 1, 4, T37);\r
- SET(d, a, b, c, 4, 11, T38);\r
- SET(c, d, a, b, 7, 16, T39);\r
- SET(b, c, d, a, 10, 23, T40);\r
- SET(a, b, c, d, 13, 4, T41);\r
- SET(d, a, b, c, 0, 11, T42);\r
- SET(c, d, a, b, 3, 16, T43);\r
- SET(b, c, d, a, 6, 23, T44);\r
- SET(a, b, c, d, 9, 4, T45);\r
- SET(d, a, b, c, 12, 11, T46);\r
- SET(c, d, a, b, 15, 16, T47);\r
- SET(b, c, d, a, 2, 23, T48);\r
-#undef SET\r
-\r
- /* Round 4. */\r
- /* Let [abcd k s t] denote the operation\r
- a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */\r
-#define I(x, y, z) ((y) ^ ((x) | ~(z)))\r
-#define SET(a, b, c, d, k, s, Ti) t = a + I(b,c,d) + X[k] + Ti; a = ROTATE_LEFT(t, s) + b\r
- /* Do the following 16 operations. */\r
- SET(a, b, c, d, 0, 6, T49);\r
- SET(d, a, b, c, 7, 10, T50);\r
- SET(c, d, a, b, 14, 15, T51);\r
- SET(b, c, d, a, 5, 21, T52);\r
- SET(a, b, c, d, 12, 6, T53);\r
- SET(d, a, b, c, 3, 10, T54);\r
- SET(c, d, a, b, 10, 15, T55);\r
- SET(b, c, d, a, 1, 21, T56);\r
- SET(a, b, c, d, 8, 6, T57);\r
- SET(d, a, b, c, 15, 10, T58);\r
- SET(c, d, a, b, 6, 15, T59);\r
- SET(b, c, d, a, 13, 21, T60);\r
- SET(a, b, c, d, 4, 6, T61);\r
- SET(d, a, b, c, 11, 10, T62);\r
- SET(c, d, a, b, 2, 15, T63);\r
- SET(b, c, d, a, 9, 21, T64);\r
-#undef SET\r
-\r
- /* Then perform the following additions. (That is increment each\r
- of the four registers by the value it had before this block\r
- was started.) */\r
- pms->abcd[0] += a;\r
- pms->abcd[1] += b;\r
- pms->abcd[2] += c;\r
- pms->abcd[3] += d;\r
-}\r
-\r
-void\r
-md5_init(md5_state_t *pms)\r
-{\r
- pms->count[0] = pms->count[1] = 0;\r
- pms->abcd[0] = 0x67452301;\r
- pms->abcd[1] = 0xefcdab89;\r
- pms->abcd[2] = 0x98badcfe;\r
- pms->abcd[3] = 0x10325476;\r
-}\r
-\r
-void\r
-md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes)\r
-{\r
- const md5_byte_t *p = data;\r
- int left = nbytes;\r
- int offset = (pms->count[0] >> 3) & 63;\r
- md5_word_t nbits = (md5_word_t)(nbytes << 3);\r
-\r
- if (nbytes <= 0)\r
- return;\r
-\r
- /* Update the message length. */\r
- pms->count[1] += nbytes >> 29;\r
- pms->count[0] += nbits;\r
- if (pms->count[0] < nbits)\r
- pms->count[1]++;\r
-\r
- /* Process an initial partial block. */\r
- if (offset) {\r
- int copy = (offset + nbytes > 64 ? 64 - offset : nbytes);\r
-\r
- memcpy(pms->buf + offset, p, copy);\r
- if (offset + copy < 64)\r
- return;\r
- p += copy;\r
- left -= copy;\r
- md5_process(pms, pms->buf);\r
- }\r
-\r
- /* Process full blocks. */\r
- for (; left >= 64; p += 64, left -= 64)\r
- md5_process(pms, p);\r
-\r
- /* Process a final partial block. */\r
- if (left)\r
- memcpy(pms->buf, p, left);\r
-}\r
-\r
-void\r
-md5_finish(md5_state_t *pms, md5_byte_t digest[16])\r
-{\r
- static const md5_byte_t pad[64] = {\r
- 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\r
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0\r
- };\r
- md5_byte_t data[8];\r
- int i;\r
-\r
- /* Save the length before padding. */\r
- for (i = 0; i < 8; ++i)\r
- data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3));\r
- /* Pad to 56 bytes mod 64. */\r
- md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1);\r
- /* Append the length. */\r
- md5_append(pms, data, 8);\r
- for (i = 0; i < 16; ++i)\r
- digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3));\r
-}\r
+/*
+ * The rest of the code is derived from MD5C.C by RSADSI. Minor cosmetic
+ * changes to accomodate it in the kernel by ji.
+ * Minor changes to make 64 bit clean by Peter Onion (i.e. using u_int*_t).
+ */
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/*
+ * Additions by JI
+ *
+ * HAVEMEMCOPY is defined if mem* routines are available
+ *
+ * HAVEHTON is defined if htons() and htonl() can be used
+ * for big/little endian conversions
+ *
+ */
+
+#include <stddef.h>
+#include <string.h>
+#include <sys/types.h> /* for u_int*_t */
+
+#include "md5.h"
+#include "endian.h" /* sets BYTE_ORDER, LITTLE_ENDIAN, and BIG_ENDIAN */
+
+#define HAVEMEMCOPY 1 /* use ISO C's memcpy and memset */
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+#define MD5Transform _MD5Transform
+
+static void MD5Transform PROTO_LIST ((UINT4 [4], unsigned char [64]));
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+#define Encode MD5_memcpy
+#define Decode MD5_memcpy
+#else
+static void Encode PROTO_LIST
+ ((unsigned char *, UINT4 *, unsigned int));
+static void Decode PROTO_LIST
+ ((UINT4 *, unsigned char *, unsigned int));
+#endif
+
+#ifdef HAVEMEMCOPY
+#include <memory.h>
+#define MD5_memcpy memcpy
+#define MD5_memset memset
+#else
+#ifdef HAVEBCOPY
+#define MD5_memcpy(_a,_b,_c) memcpy((_a), (_b),(_c))
+#define MD5_memset(_a,_b,_c) memset((_a), '\0',(_c))
+#else
+static void MD5_memcpy PROTO_LIST ((POINTER, POINTER, unsigned int));
+static void MD5_memset PROTO_LIST ((POINTER, int, unsigned int));
+#endif
+#endif
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void MD5Init (context)
+MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void MD5Update (context, input, inputLen)
+MD5_CTX *context; /* context */
+unsigned char *input; /* input block */
+UINT4 inputLen; /* length of input block */
+{
+ UINT4 i;
+ unsigned int index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += (inputLen << 3)) < (inputLen << 3))
+ context->count[1]++;
+ context->count[1] += (inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible. */
+ if (inputLen >= partLen) {
+ MD5_memcpy((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy((POINTER)&context->buffer[index], (POINTER)&input[i], inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5Update (context, bits, 8);
+
+ if (digest != NULL) /* Bill Simpson's padding */
+ {
+ /* store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+ }
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+#if BYTE_ORDER != LITTLE_ENDIAN
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+#endif
+
+#ifndef HAVEMEMCOPY
+#ifndef HAVEBCOPY
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+#endif
+#endif
+
-/*\r
- Copyright (C) 1999 Aladdin Enterprises. All rights reserved.\r
-\r
- This software is provided 'as-is', without any express or implied\r
- warranty. In no event will the authors be held liable for any damages\r
- arising from the use of this software.\r
-\r
- Permission is granted to anyone to use this software for any purpose,\r
- including commercial applications, and to alter it and redistribute it\r
- freely, subject to the following restrictions:\r
-\r
- 1. The origin of this software must not be misrepresented; you must not\r
- claim that you wrote the original software. If you use this software\r
- in a product, an acknowledgment in the product documentation would be\r
- appreciated but is not required.\r
- 2. Altered source versions must be plainly marked as such, and must not be\r
- misrepresented as being the original software.\r
- 3. This notice may not be removed or altered from any source distribution.\r
-\r
- L. Peter Deutsch\r
- ghost@aladdin.com\r
-\r
- */\r
-/*$Id: md5.h $ */\r
-/*\r
- Independent implementation of MD5 (RFC 1321).\r
-\r
- This code implements the MD5 Algorithm defined in RFC 1321.\r
- It is derived directly from the text of the RFC and not from the\r
- reference implementation.\r
-\r
- The original and principal author of md5.h is L. Peter Deutsch\r
- <ghost@aladdin.com>. Other authors are noted in the change history\r
- that follows (in reverse chronological order):\r
-\r
- 1999-11-04 lpd Edited comments slightly for automatic TOC extraction.\r
- 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5);\r
- added conditionalization for C++ compilation from Martin\r
- Purschke <purschke@bnl.gov>.\r
- 1999-05-03 lpd Original version.\r
- */\r
-\r
-#ifndef md5_INCLUDED\r
-# define md5_INCLUDED\r
-\r
-/*\r
- * This code has some adaptations for the Ghostscript environment, but it\r
- * will compile and run correctly in any environment with 8-bit chars and\r
- * 32-bit ints. Specifically, it assumes that if the following are\r
- * defined, they have the same meaning as in Ghostscript: P1, P2, P3,\r
- * ARCH_IS_BIG_ENDIAN.\r
- */\r
-\r
-typedef unsigned char md5_byte_t; /* 8-bit byte */\r
-typedef unsigned int md5_word_t; /* 32-bit word */\r
-\r
-/* Define the state of the MD5 Algorithm. */\r
-typedef struct md5_state_s {\r
- md5_word_t count[2]; /* message length in bits, lsw first */\r
- md5_word_t abcd[4]; /* digest buffer */\r
- md5_byte_t buf[64]; /* accumulate block */\r
-} md5_state_t;\r
-\r
-#ifdef __cplusplus\r
-extern "C" \r
-{\r
-#endif\r
-\r
-/* Initialize the algorithm. */\r
-#ifdef P1\r
-void md5_init(P1(md5_state_t *pms));\r
-#else\r
-void md5_init(md5_state_t *pms);\r
-#endif\r
-\r
-/* Append a string to the message. */\r
-#ifdef P3\r
-void md5_append(P3(md5_state_t *pms, const md5_byte_t *data, int nbytes));\r
-#else\r
-void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes);\r
-#endif\r
-\r
-/* Finish the message and return the digest. */\r
-#ifdef P2\r
-void md5_finish(P2(md5_state_t *pms, md5_byte_t digest[16]));\r
-#else\r
-void md5_finish(md5_state_t *pms, md5_byte_t digest[16]);\r
-#endif\r
-\r
-#ifdef __cplusplus\r
-} /* end extern "C" */\r
-#endif\r
-\r
-#endif /* md5_INCLUDED */\r
+/* GLOBAL.H - RSAREF types and constants
+ */
+
+/* PROTOTYPES should be set to one if and only if the compiler supports
+ function argument prototyping.
+ The following makes PROTOTYPES default to 0 if it has not already
+ been defined with C compiler flags.
+ */
+#ifndef PROTOTYPES
+#define PROTOTYPES 1
+#endif
+
+/* POINTER defines a generic pointer type */
+typedef unsigned char *POINTER;
+
+/* UINT2 defines a two byte word */
+typedef u_int16_t UINT2;
+
+/* UINT4 defines a four byte word */
+typedef u_int32_t UINT4;
+
+/* PROTO_LIST is defined depending on how PROTOTYPES is defined above.
+ If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it
+ returns an empty list.
+ */
+
+#if PROTOTYPES
+#define PROTO_LIST(list) list
+#else
+#define PROTO_LIST(list) ()
+#endif
+
+
+/* MD5.H - header file for MD5C.C
+ */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD5_CTX;
+
+void MD5Init PROTO_LIST ((MD5_CTX *));
+void MD5Update PROTO_LIST
+ ((MD5_CTX *, unsigned char *, UINT4));
+void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *));
+
+#define _MD5_H_
* <www.linuxvirtualserver.org>. It monitor & manipulate
* a loadbalanced server pool using multi-layer checks.
*
- * Part: Pid file lock utils.
+ * Part: pidfile utility.
*
- * Version: $Id: pidfile.c,v 0.2.6 2001/03/05 $
+ * Version: $Id: pidfile.c,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
*
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* Changes:
- * Alexandre Cassen : Initial release
+ * Alexandre Cassen : 2001/06/25 : Initial release
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
#include "pidfile.h"
+/* Create the runnnig daemon pidfile */
int pidfile_write(int pid)
{
FILE *pidfile = fopen(PIDFILENAME,"w");
if(!pidfile) {
- logmessage("pidfile_write : Can not open pidfile\n");
- return(0);
+ syslog(LOG_INFO,"pidfile_write : Can not open pidfile");
+ return 0;
}
fprintf(pidfile,"%d\n",pid);
fclose(pidfile);
- return(1);
+ return 1;
}
+/* Remove the running daemon pidfile */
void pidfile_rm()
{
unlink(PIDFILENAME);
}
+/* return the daemon running state */
int keepalived_running()
{
- FILE *pidfile;
+ FILE *pidfile = fopen(PIDFILENAME,"r");
+ pid_t pid;
- if ((pidfile=fopen(PIDFILENAME,"r")) == NULL)
- return 0;
+ /* No pidfile */
+ if (!pidfile) return 0;
+ fscanf(pidfile,"%d",&pid);
fclose(pidfile);
+
+ /* If no process is attached to pidfile, remove it */
+ if (kill(pid,0)) {
+ syslog(LOG_INFO,"Remove a zomby pid file %s.",PIDFILENAME);
+ pidfile_rm();
+ return 0;
+ }
+
+ syslog(LOG_INFO,"daemon is already running");
return 1;
}
*
* Part: pidfile.c include file.
*
- * Version: $Id: pidfile.h,v 0.2.6 2001/03/05 $
+ * Version: $Id: pidfile.h,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
*
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
*
- * Changes:
- * Alexandre Cassen : Initial release
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* 2 of the License, or (at your option) any later version.
*/
-#ifndef PIDFILE_H
-#define PIDFILE_H
+#ifndef _PIDFILE_H
+#define _PIDFILE_H
+/* system include */
#include <unistd.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <termios.h>
#include <signal.h>
#include <sys/types.h>
-#include <sys/time.h>
-#include <netdb.h>
-#include <string.h>
+#include <syslog.h>
+/* lock pidfile */
#define PIDFILENAME "/var/run/keepalived.pid"
+/* Prototypes */
+extern int pidfile_write(int pid);
+extern void pidfile_rm();
+extern int keepalived_running();
+
#endif
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: Scheduling framework. This code is highly inspired from
+ * the thread management routine (thread.c) present in the
+ * very nice zebra project (http://www.zebra.org).
+ *
+ * Version: $Id: scheduler.c,v 0.3.5 2001/07/13 03:46:52 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * Changes:
+ * Alexandre Cassen : 2001/06/08 : Initial release
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "scheduler.h"
+
+/* Make thread master. */
+struct thread_master *
+thread_make_master ()
+{
+ struct thread_master *new;
+
+ new = (struct thread_master *)malloc(sizeof (struct thread_master));
+ memset(new,0,sizeof(struct thread_master));
+
+ return new;
+}
+
+/* Make a new http thread arg */
+struct http_thread_arg *
+thread_http_checker_arg_new()
+{
+ struct http_thread_arg *new;
+
+ /* Allocate & prepare the thread argument structure */
+ new = (struct http_thread_arg *)malloc(sizeof (struct http_thread_arg));
+ memset(new, 0, sizeof(struct http_thread_arg));
+
+ return new;
+}
+
+/* Make a new global thread arg */
+struct thread_arg *
+thread_arg_new(configuration_data *root,
+ virtualserver *vserver,
+ realserver *rserver)
+{
+ struct thread_arg *new;
+
+ /* Allocate & prepare the thread argument structure */
+ new = (struct thread_arg *)malloc(sizeof (struct thread_arg));
+ memset(new, 0, sizeof(struct thread_arg));
+
+ /* Assign structure elements */
+ new->root = root;
+ new->vs = vserver;
+ new->svr = rserver;
+ new->checker_arg = NULL;
+
+ return new;
+}
+
+/* Add a new thread to the list. */
+static void
+thread_list_add (struct thread_list *list, struct thread *thread)
+{
+ thread->next = NULL;
+ thread->prev = list->tail;
+ if (list->tail)
+ list->tail->next = thread;
+ else
+ list->head = thread;
+ list->tail = thread;
+ list->count++;
+}
+
+/* Add a new thread to the list. */
+void
+thread_list_add_before (struct thread_list *list,
+ struct thread *point,
+ struct thread *thread)
+{
+ thread->next = point;
+ thread->prev = point->prev;
+ if (point->prev)
+ point->prev->next = thread;
+ else
+ list->head = thread;
+ point->prev = thread;
+ list->count++;
+}
+
+/* timer compare */
+static int
+thread_timer_cmp (struct timeval a, struct timeval b)
+{
+ if (a.tv_sec > b.tv_sec)
+ return 1;
+ if (a.tv_sec < b.tv_sec)
+ return -1;
+ if (a.tv_usec > b.tv_usec)
+ return 1;
+ if (a.tv_usec < b.tv_usec)
+ return -1;
+ return 0;
+}
+
+/* Add a thread in the list sorted by timeval */
+void
+thread_list_add_timeval(struct thread_list *list, struct thread *thread)
+{
+ struct thread *tt;
+
+ for (tt = list->head; tt; tt = tt->next)
+ if (thread_timer_cmp (thread->sands, tt->sands) <= 0)
+ break;
+
+ if (tt)
+ thread_list_add_before (list, tt, thread);
+ else
+ thread_list_add (list, thread);
+}
+
+/* Delete a thread from the list. */
+struct thread *
+thread_list_delete (struct thread_list *list, struct thread *thread)
+{
+ if (thread->next)
+ thread->next->prev = thread->prev;
+ else
+ list->tail = thread->prev;
+ if (thread->prev)
+ thread->prev->next = thread->next;
+ else
+ list->head = thread->next;
+ thread->next = thread->prev = NULL;
+ list->count--;
+ return thread;
+}
+
+/* Free all unused thread. */
+static void
+thread_clean_unuse (struct thread_master *m)
+{
+ struct thread *thread;
+
+ thread = m->unuse.head;
+ while (thread) {
+ struct thread *t;
+
+ t = thread;
+ thread = t->next;
+
+ thread_list_delete (&m->unuse, t);
+
+ /* FIXME : Need to add thread_arg memory cleanup */
+
+ /* free the thread */
+ free(t);
+ m->alloc--;
+ }
+}
+
+/* Move thread to unuse list. */
+static void
+thread_add_unuse (struct thread_master *m, struct thread *thread)
+{
+ assert (m != NULL);
+ assert (thread->next == NULL);
+ assert (thread->prev == NULL);
+ assert (thread->type == THREAD_UNUSED);
+ thread_list_add (&m->unuse, thread);
+}
+
+/* Move list element to unuse queue */
+void
+thread_destroy_list(struct thread_master *m, struct thread_list thread_list)
+{
+ struct thread *thread;
+
+ thread = thread_list.head;
+
+ while (thread) {
+ struct thread *t;
+
+ t = thread;
+ thread = t->next;
+
+ thread_list_delete (&thread_list, t);
+ t->type = THREAD_UNUSED;
+ thread_add_unuse (m, t);
+ }
+}
+
+/* Stop thread scheduler. */
+void
+thread_destroy_master (struct thread_master *m)
+{
+ thread_destroy_list(m,m->read);
+ thread_destroy_list(m,m->write);
+ thread_destroy_list(m,m->timer);
+ thread_destroy_list(m,m->event);
+ thread_destroy_list(m,m->ready);
+
+ thread_clean_unuse (m);
+ free(m);
+}
+
+/* Delete top of the list and return it. */
+struct thread *
+thread_trim_head (struct thread_list *list)
+{
+ if (list->head)
+ return thread_list_delete (list, list->head);
+ return NULL;
+}
+
+/* Make new thread. */
+struct thread *
+thread_new (struct thread_master *m)
+{
+ struct thread *new;
+
+ /* If one thread is already allocated return it */
+ if (m->unuse.head) {
+ new = thread_trim_head(&m->unuse);
+ memset(new,0,sizeof(struct thread));
+ return new;
+ }
+
+ new = (struct thread *)malloc(sizeof(struct thread));
+ memset(new,0,sizeof(struct thread));
+ m->alloc++;
+ return new;
+}
+
+/* Add new read thread. */
+struct thread *
+thread_add_read (struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg,
+ int fd,
+ long timer)
+{
+ struct thread *thread;
+ struct timeval timer_now;
+
+ assert (m != NULL);
+
+ if (FD_ISSET (fd, &m->readfd)) {
+ syslog(LOG_WARNING,"There is already read fd [%d]", fd);
+ return NULL;
+ }
+
+ thread = thread_new (m);
+ thread->type = THREAD_READ;
+ thread->id = 0;
+ thread->master = m;
+ thread->func = func;
+ thread->arg = arg;
+ FD_SET (fd, &m->readfd);
+ thread->u.fd = fd;
+
+ /* Compute read timeout value */
+ gettimeofday(&timer_now,NULL);
+ timer_now.tv_sec += timer;
+ thread->sands = timer_now;
+
+ /* Sort the thread. */
+ thread_list_add_timeval(&m->read,thread);
+
+ return thread;
+}
+
+/* Add new write thread. */
+struct thread *
+thread_add_write (struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg,
+ int fd,
+ long timer)
+{
+ struct thread *thread;
+ struct timeval timer_now;
+
+ assert (m != NULL);
+
+ if (FD_ISSET (fd, &m->writefd)) {
+ syslog(LOG_WARNING, "There is already write fd [%d]", fd);
+ return NULL;
+ }
+
+ thread = thread_new (m);
+ thread->type = THREAD_WRITE;
+ thread->id = 0;
+ thread->master = m;
+ thread->func = func;
+ thread->arg = arg;
+ FD_SET (fd, &m->writefd);
+ thread->u.fd = fd;
+
+ /* Compute write timeout value */
+ gettimeofday(&timer_now,NULL);
+ timer_now.tv_sec += timer;
+ thread->sands = timer_now;
+
+ /* Sort the thread. */
+ thread_list_add_timeval(&m->write,thread);
+
+ return thread;
+}
+
+/* Add timer event thread. */
+struct thread *
+thread_add_timer (struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg,
+ long timer)
+{
+ struct timeval timer_now;
+ struct thread *thread;
+
+ assert (m != NULL);
+
+ thread = thread_new (m);
+ thread->type = THREAD_TIMER;
+ thread->id = 0;
+ thread->master = m;
+ thread->func = func;
+ thread->arg = arg;
+
+ /* Do we need jitter here? */
+ gettimeofday (&timer_now, NULL);
+ timer_now.tv_sec += timer;
+ thread->sands = timer_now;
+
+ /* Sort by timeval. */
+ thread_list_add_timeval(&m->timer, thread);
+
+ return thread;
+}
+
+/* Add simple event thread. */
+struct thread *
+thread_add_event (struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg,
+ int val)
+{
+ struct thread *thread;
+
+ assert (m != NULL);
+
+ thread = thread_new (m);
+ thread->type = THREAD_EVENT;
+ thread->id = 0;
+ thread->master = m;
+ thread->func = func;
+ thread->arg = arg;
+ thread->u.val = val;
+ thread_list_add (&m->event, thread);
+
+ return thread;
+}
+
+/* Add simple event thread. */
+struct thread *
+thread_add_terminate_event (struct thread_master *m)
+{
+ struct thread *thread;
+
+ assert (m != NULL);
+
+ thread = thread_new (m);
+ thread->type = THREAD_TERMINATE;
+ thread->id = 0;
+ thread->master = m;
+ thread->func = NULL;
+ thread->arg = NULL;
+ thread->u.val = 0;
+ thread_list_add (&m->event, thread);
+
+ return thread;
+}
+
+/* Cancel thread from scheduler. */
+void
+thread_cancel (struct thread *thread)
+{
+ switch (thread->type) {
+ case THREAD_READ:
+ assert (FD_ISSET (thread->u.fd, &thread->master->readfd));
+ FD_CLR (thread->u.fd, &thread->master->readfd);
+ thread_list_delete (&thread->master->read, thread);
+ break;
+ case THREAD_WRITE:
+ assert (FD_ISSET (thread->u.fd, &thread->master->writefd));
+ FD_CLR (thread->u.fd, &thread->master->writefd);
+ thread_list_delete (&thread->master->write, thread);
+ break;
+ case THREAD_TIMER:
+ thread_list_delete (&thread->master->timer, thread);
+ break;
+ case THREAD_EVENT:
+ thread_list_delete (&thread->master->event, thread);
+ break;
+ case THREAD_READY:
+ thread_list_delete (&thread->master->ready, thread);
+ break;
+ default:
+ break;
+ }
+
+ thread->type = THREAD_UNUSED;
+ thread_add_unuse (thread->master, thread);
+}
+
+/* Delete all events which has argument value arg. */
+void
+thread_cancel_event (struct thread_master *m, void *arg)
+{
+ struct thread *thread;
+
+ thread = m->event.head;
+ while (thread) {
+ struct thread *t;
+
+ t = thread;
+ thread = t->next;
+
+ if (t->arg == arg) {
+ thread_list_delete (&m->event, t);
+ t->type = THREAD_UNUSED;
+ thread_add_unuse (m, t);
+ }
+ }
+}
+
+/* for struct timeval */
+#define TIMER_SEC_MICRO 1000000
+
+/* timer sub */
+struct timeval
+thread_timer_sub (struct timeval a, struct timeval b)
+{
+ struct timeval ret;
+
+ ret.tv_usec = a.tv_usec - b.tv_usec;
+ ret.tv_sec = a.tv_sec - b.tv_sec;
+
+ if (ret.tv_usec < 0) {
+ ret.tv_usec += TIMER_SEC_MICRO;
+ ret.tv_sec--;
+ }
+
+ return ret;
+}
+
+/* Compute the wait timer. Take care of timeouted fd */
+struct timeval *
+thread_compute_timer(struct thread_master *m, struct timeval *timer_wait)
+{
+ struct timeval timer_now;
+ struct timeval timer_min;
+
+ if (m->timer.head) {
+ gettimeofday (&timer_now, NULL);
+
+ /* Compare write(sands) to timer(sands) */
+ if (m->write.head) {
+ if (thread_timer_cmp(m->timer.head->sands,
+ m->write.head->sands) <= 0)
+ timer_min = m->timer.head->sands;
+ else
+ if (m->write.head->sands.tv_sec != 0)
+ timer_min = m->write.head->sands;
+ else
+ timer_min = m->timer.head->sands;
+ } else
+ timer_min = m->timer.head->sands;
+
+ /* Compare read to min(write(sands),timer(sands)) */
+ if (m->read.head) {
+ if (thread_timer_cmp(m->read.head->sands,
+ timer_min) <= 0)
+ timer_min = m->read.head->sands;
+ else
+ if (m->read.head->sands.tv_sec != 0)
+ timer_min = m->read.head->sands;
+ }
+
+ timer_min = thread_timer_sub (timer_min, timer_now);
+ if (timer_min.tv_sec < 0) {
+ timer_min.tv_sec = 0;
+ timer_min.tv_usec = 10;
+ }
+ timer_wait->tv_sec = timer_min.tv_sec;
+ timer_wait->tv_usec = timer_min.tv_usec;
+ } else {
+ if (m->write.head && (m->write.head->sands.tv_sec != 0)) {
+ gettimeofday (&timer_now, NULL);
+ timer_min = m->write.head->sands;
+ timer_min = thread_timer_sub(timer_min,timer_now);
+ if (timer_min.tv_sec < 0) {
+ timer_min.tv_sec = 0;
+ timer_min.tv_usec = 10;
+ }
+ timer_wait->tv_sec = timer_min.tv_sec;
+ timer_wait->tv_usec = timer_min.tv_usec;
+ } else
+ timer_wait = NULL;
+ }
+
+ return timer_wait;
+}
+
+/* Fetch next ready thread. */
+struct thread *
+thread_fetch (struct thread_master *m, struct thread *fetch)
+{
+ int ret;
+ struct thread *thread;
+ fd_set readfd;
+ fd_set writefd;
+ fd_set exceptfd;
+ struct timeval timer_now;
+ struct timeval *timer_wait;
+
+ assert (m != NULL);
+
+ /* Timer allocation */
+ timer_wait = (struct timeval *)malloc(sizeof(struct timeval));
+ memset(timer_wait,0,sizeof(struct timeval));
+
+retry: /* When thread can't fetch try to find next thread again. */
+
+ /* If there is event process it first. */
+ while ((thread = thread_trim_head (&m->event))) {
+ *fetch = *thread;
+ free(timer_wait);
+
+ /* If daemon hanging event is received return NULL pointer */
+ if (thread->type == THREAD_TERMINATE) {
+ thread->type = THREAD_UNUSED;
+ thread_add_unuse (m, thread);
+ return NULL;
+ }
+ thread->type = THREAD_UNUSED;
+ thread_add_unuse (m, thread);
+ return fetch;
+ }
+
+ /* If there is ready threads process them */
+ while ((thread = thread_trim_head (&m->ready))) {
+ *fetch = *thread;
+ thread->type = THREAD_UNUSED;
+ thread_add_unuse (m, thread);
+ free(timer_wait);
+ return fetch;
+ }
+
+ /* Calculate select wait timer. Take care of timeouted fd */
+ timer_wait = thread_compute_timer(m, timer_wait);
+
+ /* Call select function. */
+ readfd = m->readfd;
+ writefd = m->writefd;
+ exceptfd = m->exceptfd;
+
+ ret = select (FD_SETSIZE, &readfd, &writefd, &exceptfd, timer_wait);
+ if (ret < 0) {
+ if (errno != EINTR) {
+ /* Real error. */
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "select error: %s", strerror (errno));
+#endif
+ assert (0);
+ }
+ /* Signal is coming. */
+ goto retry;
+ }
+
+ /* Read thead. */
+ gettimeofday (&timer_now, NULL);
+ thread = m->read.head;
+
+ while (thread) {
+ struct thread *t;
+
+ t = thread;
+ thread = t->next;
+
+ if (FD_ISSET (t->u.fd, &readfd)) {
+ assert (FD_ISSET (t->u.fd, &m->readfd));
+ FD_CLR(t->u.fd, &m->readfd);
+ thread_list_delete (&m->read, t);
+ thread_list_add (&m->ready, t);
+ t->type = THREAD_READY;
+ } else {
+ if (thread_timer_cmp(timer_now, t->sands) >= 0) {
+ FD_CLR(t->u.fd, &m->readfd);
+ thread_list_delete (&m->read, t);
+ thread_list_add (&m->ready, t);
+ t->type = THREAD_READ_TIMEOUT;
+ }
+ }
+ }
+
+ /* Write thead. */
+ gettimeofday (&timer_now, NULL);
+ thread = m->write.head;
+
+ while (thread) {
+ struct thread *t;
+
+ t = thread;
+ thread = t->next;
+
+ if (FD_ISSET (t->u.fd, &writefd)) {
+ assert (FD_ISSET (t->u.fd, &writefd));
+ FD_CLR(t->u.fd, &m->writefd);
+ thread_list_delete (&m->write, t);
+ thread_list_add (&m->ready, t);
+ t->type = THREAD_READY;
+ } else {
+ if (thread_timer_cmp(timer_now, t->sands) >= 0) {
+ FD_CLR(t->u.fd, &m->writefd);
+ thread_list_delete (&m->write, t);
+ thread_list_add (&m->ready, t);
+ t->type = THREAD_WRITE_TIMEOUT;
+ }
+ }
+ }
+ /* Exception thead. */
+ /*...*/
+
+ /* Timer update. */
+ gettimeofday (&timer_now, NULL);
+
+ thread = m->timer.head;
+ while (thread) {
+ struct thread *t;
+
+ t = thread;
+ thread = t->next;
+
+ if (thread_timer_cmp (timer_now, t->sands) >= 0) {
+ thread_list_delete (&m->timer, t);
+ thread_list_add (&m->ready, t);
+ t->type = THREAD_READY;
+ }
+ }
+
+ /* Return one event. */
+ thread = thread_trim_head (&m->ready);
+
+ /* There is no ready thread. */
+ if (!thread)
+ goto retry;
+
+ *fetch = *thread;
+ thread->type = THREAD_UNUSED;
+ thread_add_unuse (m, thread);
+
+ free(timer_wait);
+ return fetch;
+}
+
+/* Make unique thread id for non pthread version of thread manager. */
+unsigned long int
+thread_get_id ()
+{
+ static unsigned long int counter = 0;
+ return ++counter;
+}
+
+/* Call thread ! */
+void
+thread_call (struct thread *thread)
+{
+ thread->id = thread_get_id ();
+ (*thread->func) (thread);
+}
+
+/* Register worker thread. One per realserver of each virtualserver */
+void
+register_vs_worker_thread(struct thread_master *master,
+ configuration_data *root,
+ virtualserver *lstptr)
+{
+ realserver *pointersvr;
+ struct thread_arg *thread_arg;
+
+ pointersvr = lstptr->svr;
+
+ while (lstptr->svr) {
+
+ switch (lstptr->svr->method->type) {
+ case TCP_CHECK_ID:
+ thread_arg = thread_arg_new(root, lstptr, lstptr->svr);
+ thread_add_timer(master, tcp_connect_thread, thread_arg,
+ thread_arg->vs->delay_loop);
+ break;
+ case HTTP_GET_ID:
+ thread_arg = thread_arg_new(root, lstptr, lstptr->svr);
+ thread_arg->checker_arg = (struct http_thread_arg *)thread_http_checker_arg_new();
+ thread_add_timer(master, http_connect_thread, thread_arg,
+ thread_arg->vs->delay_loop);
+ break;
+ case SSL_GET_ID:
+ break;
+ case LDAP_GET_ID:
+ break;
+ default:
+ break;
+ }
+
+ lstptr->svr = (realserver *)lstptr->svr->next;
+ }
+
+ lstptr->svr = pointersvr;
+}
+
+/* Register each virtualserver realservers worker thread */
+void
+register_worker_thread(struct thread_master *master, configuration_data *lstptr)
+{
+ virtualserver *pointervs;
+
+ pointervs = lstptr->lvstopology;
+
+ while (lstptr->lvstopology) {
+ register_vs_worker_thread(master, lstptr, lstptr->lvstopology);
+
+ lstptr->lvstopology = (virtualserver *)lstptr->lvstopology->next;
+ }
+
+ lstptr->lvstopology = pointervs;
+}
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: scheduler.c include file.
+ *
+ * Version: $Id: scheduler.h,v 0.3.5 2001/07/13 03:46:52 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _SCHEDULER_H
+#define _SCHEDULER_H
+
+/* system includes */
+#include <sys/time.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <errno.h>
+
+/* local includes */
+#include "cfreader.h"
+#include "check.h"
+
+/* Linked list of thread. */
+struct thread_list
+{
+ struct thread *head;
+ struct thread *tail;
+ int count;
+};
+
+/* Master of the theads. */
+struct thread_master
+{
+ struct thread_list read;
+ struct thread_list write;
+ struct thread_list timer;
+ struct thread_list event;
+ struct thread_list ready;
+ struct thread_list unuse;
+ fd_set readfd;
+ fd_set writefd;
+ fd_set exceptfd;
+ unsigned long alloc;
+};
+
+/* Thread itself. */
+struct thread
+{
+ unsigned long id;
+ unsigned char type; /* thread type */
+ struct thread *next; /* next pointer of the thread */
+ struct thread *prev; /* previous pointer of the thread */
+ struct thread_master *master; /* pointer to the struct thread_master. */
+ int (*func) (struct thread *); /* event function */
+ void *arg; /* event argument */
+ struct timeval sands; /* rest of time sands value. */
+ union {
+ int val; /* second argument of the event. */
+ int fd; /* file descriptor in case of read/write. */
+ } u;
+};
+
+/* Thread types. */
+#define THREAD_READ 0
+#define THREAD_WRITE 1
+#define THREAD_TIMER 2
+#define THREAD_EVENT 3
+#define THREAD_READY 4
+#define THREAD_UNUSED 5
+#define THREAD_WRITE_TIMEOUT 6
+#define THREAD_READ_TIMEOUT 7
+#define THREAD_TERMINATE 8
+
+/* Macros. */
+#define THREAD_ARG(X) ((X)->arg)
+#define THREAD_ARG_CHECKER_ARG(X) ((X)->checker_arg)
+#define THREAD_FD(X) ((X)->u.fd)
+#define THREAD_VAL(X) ((X)->u.val)
+
+/* Prototypes. */
+struct thread_master *thread_make_master ();
+
+struct thread *
+thread_add_terminate_event (struct thread_master *m);
+
+void
+thread_destroy_master (struct thread_master *m);
+
+struct thread_arg *
+thread_arg_new (configuration_data *root,
+ virtualserver *vserver,
+ realserver *rserver);
+
+struct thread *
+thread_add_read (struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg,
+ int fd,
+ long timeout);
+
+struct thread *
+thread_add_write (struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg,
+ int fd,
+ long timeout);
+
+struct thread *
+thread_add_timer (struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg,
+ long timer);
+
+struct thread *
+thread_add_event (struct thread_master *m,
+ int (*func)(struct thread *),
+ void *arg,
+ int val);
+
+
+void
+thread_cancel (struct thread *thread);
+
+void
+thread_cancel_event (struct thread_master *m, void *arg);
+
+struct thread *
+thread_fetch (struct thread_master *m,
+ struct thread *fetch);
+
+void
+thread_call (struct thread *thread);
+
+struct timeval
+thread_timer_sub (struct timeval a, struct timeval b);
+
+void
+register_worker_thread(struct thread_master *master,
+ configuration_data *lstptr);
+
+/* extern prototypes */
+extern int
+tcp_connect_thread(struct thread *thread);
+
+extern int
+http_connect_thread(struct thread *thread);
+
+#endif
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: SMTP WRAPPER connect to a specified smtp server and send mail
+ * using the smtp protocol according to the RFC 821. A non blocking
+ * timeouted connection is used to handle smtp protocol.
+ *
+ * Version: $Id: smtp.c,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * Changes:
+ * Alexandre Cassen : 2001/07/15 : Initial release
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include "smtp.h"
+
+/* static prototype */
+static int smtp_send_cmd_thread(struct thread *thread);
+
+static void free_smtp_arg(struct smtp_thread_arg *smtp_arg)
+{
+ free(smtp_arg->subject);
+ free(smtp_arg->body);
+ free(smtp_arg);
+}
+
+static char *fetch_next_email(struct thread_arg *thread_arg)
+{
+ struct smtp_thread_arg *smtp_arg;
+ int i = 0;
+
+ smtp_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+
+ for (i=0; i<smtp_arg->email_it; i++)
+ thread_arg->root->email = (notification_email *)thread_arg->root->email->next;
+
+ if (thread_arg->root->email)
+ return thread_arg->root->email->addr;
+
+ return NULL;
+}
+
+static int smtp_read_cmd_thread(struct thread *thread)
+{
+ struct thread_arg *thread_arg;
+ struct smtp_thread_arg *smtp_arg;
+ notification_email *pointeremail;
+ char *fetched_email;
+ long total_length = 0;
+ int rcv_buffer_size = 0;
+ char *buffer;
+ char *buffer_tmp;
+
+ thread_arg = THREAD_ARG(thread);
+ smtp_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+
+ if (thread->type == THREAD_READ_TIMEOUT) {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Timeout reading data to remote SMTP server [%s:%d].",
+ inet_ntoa(thread_arg->root->smtp_server),
+ SMTP_PORT);
+#endif
+ free_smtp_arg(smtp_arg);
+ thread_arg->checker_arg = NULL;
+ close(thread->u.fd);
+ return 0;
+ }
+
+ /* Allocate the get buffers */
+ buffer = (char *)malloc(SMTP_BUFFER_MAX);
+ buffer_tmp = (char *)malloc(SMTP_BUFFER_LENGTH);
+
+ /* Cleanup the room */
+ memset(buffer, 0, SMTP_BUFFER_MAX);
+ memset(buffer_tmp, 0, SMTP_BUFFER_LENGTH);
+
+ while ((rcv_buffer_size = read(thread->u.fd, buffer_tmp, SMTP_BUFFER_LENGTH)) != 0) {
+ if (rcv_buffer_size == -1) {
+ if (errno == EAGAIN) goto end;
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Error reading data to remote SMTP server [%s:%d].",
+ inet_ntoa(thread_arg->root->smtp_server),
+ SMTP_PORT);
+#endif
+ free_smtp_arg(smtp_arg);
+ thread_arg->checker_arg = NULL;
+ close(thread->u.fd);
+ free(buffer);
+ free(buffer_tmp);
+ return 0;
+ }
+
+ /* received data overflow buffer size ? */
+ if (total_length >= SMTP_BUFFER_MAX) {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Received buffer from remote SMTP server [%s:%d]"
+ " overflow our get read buffer length.",
+ inet_ntoa(thread_arg->root->smtp_server),
+ SMTP_PORT);
+#endif
+ free_smtp_arg(smtp_arg);
+ thread_arg->checker_arg = NULL;
+ close(thread->u.fd);
+ free(buffer);
+ free(buffer_tmp);
+ return 0;
+ } else {
+ memcpy(buffer+total_length, buffer_tmp, rcv_buffer_size);
+ memset(buffer_tmp, 0, SMTP_BUFFER_LENGTH);
+ total_length += rcv_buffer_size;
+ if (rcv_buffer_size < SMTP_BUFFER_LENGTH) goto end;
+ }
+ }
+
+end:
+
+//printf("Received : %s", buffer);
+
+ /* setting the next stage */
+ switch (smtp_arg->stage) {
+ case connection:
+ if (memcmp(buffer, SMTP_CONNECT, 3) == 0) {
+ smtp_arg->stage = helo;
+ } else {
+ syslog(LOG_DEBUG, "Error connecting smtp server : [%s]", buffer);
+ smtp_arg->stage = error;
+ }
+ break;
+
+ case helo:
+ if (memcmp(buffer, SMTP_HELO, 3) == 0) {
+ smtp_arg->stage = mail;
+ } else {
+ syslog(LOG_DEBUG, "Error processing HELO cmd : [%s]", buffer);
+ smtp_arg->stage = error;
+ }
+ break;
+
+ case mail:
+ if (memcmp(buffer, SMTP_MAIL_FROM, 3) == 0) {
+ smtp_arg->stage = rcpt;
+ } else {
+ syslog(LOG_DEBUG, "Error processing MAIL FROM cmd : [%s]", buffer);
+ smtp_arg->stage = error;
+ }
+ break;
+
+ case rcpt:
+ if (memcmp(buffer, SMTP_RCPT_TO, 3) == 0) {
+ smtp_arg->email_it++;
+
+ pointeremail = thread_arg->root->email;
+ fetched_email = fetch_next_email(thread_arg);
+ thread_arg->root->email = pointeremail;
+
+ if (!fetched_email)
+ smtp_arg->stage = data;
+ } else {
+ syslog(LOG_DEBUG, "Error processing RCPT TO cmd : [%s]", buffer);
+ smtp_arg->stage = error;
+ }
+ break;
+
+ case data:
+ if (memcmp(buffer, SMTP_DATA, 3) == 0) {
+ smtp_arg->stage = body;
+ } else {
+ syslog(LOG_DEBUG, "Error processing DATA cmd : [%s]", buffer);
+ smtp_arg->stage = error;
+ }
+ break;
+
+ case body:
+ if (memcmp(buffer, SMTP_DOT, 3) == 0) {
+ smtp_arg->stage = quit;
+ syslog(LOG_INFO, "SMTP alert successfully sent.");
+ } else {
+ syslog(LOG_DEBUG, "Error processing DOT cmd : [%s]", buffer);
+ smtp_arg->stage = error;
+ }
+ break;
+
+ case quit:
+ /* final state, we are disconnected from the remote host */
+ free_smtp_arg(smtp_arg);
+ thread_arg->checker_arg = NULL;
+ close(thread->u.fd);
+ free(buffer);
+ free(buffer_tmp);
+ return 0;
+ break;
+
+ case error:
+ break;
+ }
+
+ /* Registering next smtp command processing thread */
+ thread_add_write(thread->master, smtp_send_cmd_thread, thread_arg, thread->u.fd,
+ thread_arg->root->smtp_connection_to);
+
+ free(buffer);
+ free(buffer_tmp);
+ return 0;
+}
+
+/* Getting localhost official canonical name */
+static char *get_local_name()
+{
+ struct hostent *host;
+ struct utsname name;
+
+ if (uname(&name) < 0)
+ return NULL;
+
+ if (!(host = gethostbyname(name.nodename)))
+ return NULL;
+
+ return host->h_name;
+}
+
+static int smtp_send_cmd_thread(struct thread *thread)
+{
+ struct thread_arg *thread_arg;
+ struct smtp_thread_arg *smtp_arg;
+ notification_email *pointeremail;
+ char *fetched_email;
+ char *buffer;
+
+ thread_arg = THREAD_ARG(thread);
+ smtp_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+
+ if (thread->type == THREAD_WRITE_TIMEOUT) {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Timeout sending data to remote SMTP server [%s:%d].",
+ inet_ntoa(thread_arg->root->smtp_server),
+ SMTP_PORT);
+#endif
+ free_smtp_arg(smtp_arg);
+ thread_arg->checker_arg = NULL;
+ close(thread->u.fd);
+ return 0;
+ }
+
+ /* allocate temporary command buffer */
+ buffer = (char *)malloc(SMTP_BUFFER_MAX);
+ memset(buffer, 0, SMTP_BUFFER_MAX);
+
+ switch (smtp_arg->stage) {
+ case connection:
+ break;
+
+ case helo:
+ snprintf(buffer, TEMP_BUFFER_LENGTH, SMTP_HELO_CMD, get_local_name());
+ if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1)
+ smtp_arg->stage = error;
+ break;
+
+ case mail:
+ snprintf(buffer, TEMP_BUFFER_LENGTH, SMTP_MAIL_CMD, thread_arg->root->email_from);
+ if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1)
+ smtp_arg->stage = error;
+ break;
+
+ case rcpt:
+ /* We send RCPT TO command multiple time to add all our email receivers.
+ * --rfc821.3.1
+ */
+ pointeremail = thread_arg->root->email;
+ fetched_email = fetch_next_email(thread_arg);
+ thread_arg->root->email = pointeremail;
+
+ snprintf(buffer, TEMP_BUFFER_LENGTH, SMTP_RCPT_CMD, fetched_email);
+ if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1)
+ smtp_arg->stage = error;
+ break;
+
+ case data:
+ if (send(thread->u.fd, SMTP_DATA_CMD, strlen(SMTP_DATA_CMD), 0) == -1)
+ smtp_arg->stage = error;
+ break;
+
+ case body:
+ snprintf(buffer, TEMP_BUFFER_LENGTH, SMTP_SUBJECT_CMD, smtp_arg->subject);
+ /* send the subject field */
+ if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1)
+ smtp_arg->stage = error;
+
+ memset(buffer, 0, SMTP_BUFFER_MAX);
+ snprintf(buffer, TEMP_BUFFER_LENGTH, SMTP_BODY_CMD, smtp_arg->body);
+ /* send the the body field */
+ if (send(thread->u.fd, buffer, strlen(buffer), 0) == -1)
+ smtp_arg->stage = error;
+
+ /* send the sending dot */
+ if (send(thread->u.fd, SMTP_SEND_CMD, strlen(SMTP_SEND_CMD), 0) == -1)
+ smtp_arg->stage = error;
+ break;
+
+ case quit:
+ if (send(thread->u.fd, SMTP_QUIT_CMD, strlen(SMTP_QUIT_CMD), 0) == -1)
+ smtp_arg->stage = error;
+ break;
+
+ case error:
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Can not send data to remote SMTP server [%s:%d].",
+ inet_ntoa(thread_arg->root->smtp_server),
+ SMTP_PORT);
+#endif
+ /* we just cleanup the room */
+ free_smtp_arg(smtp_arg);
+ thread_arg->checker_arg = NULL;
+ close(thread->u.fd);
+ free(buffer);
+ return 0;
+ break;
+ }
+
+//printf("Sending : %s", buffer);
+
+ /* Registering next smtp command processing thread */
+ thread_add_read(thread->master, smtp_read_cmd_thread, thread_arg, thread->u.fd,
+ thread_arg->root->smtp_connection_to);
+
+ free(buffer);
+ return 0;
+}
+
+/* SMTP checkers threads */
+static int smtp_check_thread(struct thread *thread)
+{
+ struct thread_arg *thread_arg;
+ struct smtp_thread_arg *smtp_arg;
+ int status;
+
+ thread_arg = THREAD_ARG(thread);
+ smtp_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+
+ status = tcp_socket_state(thread->u.fd, thread, smtp_check_thread);
+
+ switch (status) {
+ case connect_error:
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Error connecting SMTP server [%s:%d].",
+ inet_ntoa(thread_arg->root->smtp_server),
+ SMTP_PORT);
+#endif
+ free_smtp_arg(smtp_arg);
+ thread_arg->checker_arg = NULL;
+ break;
+
+ case connect_timeout:
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Timeout writing data to SMTP server [%s:%d].",
+ inet_ntoa(thread_arg->root->smtp_server),
+ SMTP_PORT);
+#endif
+ free_smtp_arg(smtp_arg);
+ thread_arg->checker_arg = NULL;
+ break;
+
+ case connect_success:
+ /* Remote SMTP server is connected.
+ * Register the next step thread smtp_cmd_thread.
+ */
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Remote SMTP server [%s:%d] connected.",
+ inet_ntoa(thread_arg->root->smtp_server),
+ SMTP_PORT);
+#endif
+
+ thread_add_write(thread->master, smtp_send_cmd_thread, thread_arg, thread->u.fd,
+ thread_arg->root->smtp_connection_to);
+ break;
+ }
+
+ return 0;
+}
+
+static int smtp_connect_thread(struct thread *thread)
+{
+ struct thread_arg *thread_arg;
+ struct smtp_thread_arg *smtp_arg;
+ int fd;
+ enum connect_result status;
+
+ thread_arg = THREAD_ARG(thread);
+ smtp_arg = THREAD_ARG_CHECKER_ARG(thread_arg);
+
+ if ( (fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) {
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "SMTP connect fail to create socket.");
+#endif
+ return 0;
+ }
+
+ status = tcp_connect(fd, thread_arg->root->smtp_server.s_addr, htons(SMTP_PORT));
+
+ switch (status) {
+ case connect_error:
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "SMTP connection ERROR to [%s:%d].",
+ inet_ntoa(thread_arg->root->smtp_server),
+ SMTP_PORT);
+#endif
+ free_smtp_arg(smtp_arg);
+ thread_arg->checker_arg = NULL;
+ close(fd);
+ return 0;
+ break;
+
+ case connect_timeout:
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "Timeout connecting SMTP server [%s:%d].",
+ inet_ntoa(thread_arg->root->smtp_server),
+ SMTP_PORT);
+#endif
+ free_smtp_arg(smtp_arg);
+ thread_arg->checker_arg = NULL;
+ close(fd);
+ return 0;
+ break;
+
+ case connect_success:
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "SMTP connection SUCCESS to [%s:%d].",
+ inet_ntoa(thread_arg->root->smtp_server),
+ SMTP_PORT);
+#endif
+ break;
+
+ /* Checking non-blocking connect, we wait until socket is writable */
+ case connect_in_progress:
+#ifdef DEBUG
+ syslog(LOG_DEBUG, "SMTP connection to [%s:%d] now IN_PROGRESS.",
+ inet_ntoa(thread_arg->root->smtp_server),
+ SMTP_PORT);
+#endif
+ break;
+ }
+
+ /* connection have succeeded or still in progress */
+ thread_add_write(thread->master, smtp_check_thread, thread_arg, fd,
+ thread_arg->root->smtp_connection_to);
+
+ return 1;
+}
+
+void smtp_alert(struct thread_master *master,
+ configuration_data *root,
+ realserver *rserver,
+ const char *subject,
+ const char *body)
+{
+ struct thread_arg *thread_arg;
+ struct smtp_thread_arg *smtp_arg;
+
+ /* allocate a new thread_arg */
+ thread_arg = thread_arg_new(root, NULL, NULL);
+
+ /* allocate & initialize smtp argument data structure */
+ smtp_arg = (struct smtp_thread_arg *)malloc(sizeof(struct smtp_thread_arg));
+ memset(smtp_arg, 0, sizeof(struct smtp_thread_arg));
+
+ smtp_arg->subject = (char *)malloc(MAX_SUBJECT_LENGTH);
+ smtp_arg->body = (char *)malloc(MAX_BODY_LENGTH);
+ memset(smtp_arg->subject, 0, MAX_SUBJECT_LENGTH);
+ memset(smtp_arg->body, 0, MAX_BODY_LENGTH);
+
+ smtp_arg->stage = connection; /* first smtp command set to HELO */
+
+ /* format subject if rserver is specified */
+ if (rserver)
+ snprintf(smtp_arg->subject, MAX_SUBJECT_LENGTH, "[%s] %s:%d - %s",
+ root->lvs_id, inet_ntoa(rserver->addr_ip), ntohs(rserver->addr_port), subject);
+ else
+ snprintf(smtp_arg->subject, MAX_SUBJECT_LENGTH, "[%s] %s", root->lvs_id, subject);
+
+ strncpy(smtp_arg->body, body, MAX_BODY_LENGTH);
+
+ thread_arg->checker_arg = smtp_arg;
+
+ thread_add_event(master, smtp_connect_thread, thread_arg, 0);
+}
--- /dev/null
+/*
+ * Soft: Keepalived is a failover program for the LVS project
+ * <www.linuxvirtualserver.org>. It monitor & manipulate
+ * a loadbalanced server pool using multi-layer checks.
+ *
+ * Part: smtp.c include file.
+ *
+ * Version: $Id: smtp.c,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
+ *
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef _HTTP_H
+#define _HTTP_H
+
+/* globales includes */
+#include <netdb.h>
+#include <sys/param.h>
+#include <sys/utsname.h>
+
+/* local includes */
+#include "cfreader.h"
+#include "scheduler.h"
+#include "layer4.h"
+
+/* global defs */
+#define SMTP_PORT 25
+#define SMTP_BUFFER_LENGTH 128
+#define SMTP_BUFFER_MAX 256
+
+/* command stage */
+enum smtp_cmd {
+ connection,
+ helo,
+ mail,
+ rcpt,
+ data,
+ body,
+ quit,
+ error
+};
+
+/* SMTP thread argument structure */
+#define MAX_SUBJECT_LENGTH 256
+#define MAX_BODY_LENGTH 512
+
+struct smtp_thread_arg {
+ enum smtp_cmd stage;
+ int email_it;
+ char *subject;
+ char *body;
+};
+
+/* Smtp error code */
+#define SMTP_CONNECT "220"
+#define SMTP_HELO "250"
+#define SMTP_MAIL_FROM "250"
+#define SMTP_RCPT_TO "250"
+#define SMTP_DATA "354"
+#define SMTP_DOT "250"
+
+/* Smtp command string processing */
+#define SMTP_HELO_CMD "HELO %s\n"
+#define SMTP_MAIL_CMD "MAIL FROM:%s\n"
+#define SMTP_RCPT_CMD "RCPT TO:%s\n"
+#define SMTP_DATA_CMD "DATA\n"
+#define SMTP_SUBJECT_CMD "Subject: %s\nX-Mailer: Keepalived\n\n"
+#define SMTP_BODY_CMD "\n\n%s\n\n"
+#define SMTP_SEND_CMD "\n.\n"
+#define SMTP_QUIT_CMD "QUIT\n"
+
+/* Prototypes defs */
+extern void smtp_alert(struct thread_master *master,
+ configuration_data *root,
+ realserver *rserver,
+ const char *subject,
+ const char *body);
+
+#endif
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: SMTP WRAPPER connect to a specified smtp server and send mail
- * using the smtp protocol according to the RFC 822. A non blocking
- * timeouted connection is used to handle smtp protocol.
- *
- * Version: $Id: smtpwrapper.c,v 0.2.6 2001/03/01 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : 2001/03/01 : Initial release
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include "smtpwrapper.h"
-
-int send_to(register int sdesc, fd_set wfds, struct timeval tv, char *buffer)
-{
- select(sdesc+1,NULL,&wfds,NULL,&tv);
- if (!FD_ISSET(sdesc,&wfds)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Timeout writing data to smtp server\n");
-#endif
- return(SOCKET_ERROR);
- }
-
- if (send(sdesc,buffer,strlen(buffer),0) == -1) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Can not send data to remote smtp server\n");
-#endif
- return(SOCKET_ERROR);
- }
-
- return(SOCKET_SUCCESS);
-}
-
-int read_to(register int sdesc, fd_set rfds, struct timeval tv, char *buffer)
-{
- int rcv_buffer_size=0;
- long total_length=0;
- char *buffertmp;
-
- buffertmp=(char *)malloc(BUFFER_LENGTH);
- memset(buffertmp,0,BUFFER_LENGTH);
-
- select(sdesc+1,&rfds,NULL,NULL,&tv);
- if (!FD_ISSET(sdesc,&rfds)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Timeout receiving data from smtp server\n");
-#endif
- free(buffertmp);
- return(SOCKET_ERROR);
- }
-
- while((rcv_buffer_size = read(sdesc,buffertmp,BUFFER_LENGTH)) != 0) {
- if ( rcv_buffer_size == -1 ) {
- if(errno == EAGAIN) goto end;
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Can not recieve data from remote smtp server\n");
-#endif
- free(buffertmp);
- return(SOCKET_ERROR);
- }
- memcpy(buffer+total_length,buffertmp,rcv_buffer_size);
- memset(buffertmp,0,BUFFER_LENGTH);
- total_length += rcv_buffer_size;
- }
-
-end:
- free(buffertmp);
- return(SOCKET_SUCCESS);
-}
-
-int smtp_cmd(register int sdesc,fd_set rfds,fd_set wfds,struct timeval tv,char *smtpcmd,char *retcode)
-{
- char *buffer;
- char *smtpcode;
-
- buffer=(char *)malloc(BUFFER_LENGTH);
- smtpcode=(char *)malloc(SMTP_ERROR_CODE_LENGTH);
-
- /* Sending SMTP command to remote smtp server */
- if (!send_to(sdesc,wfds,tv,smtpcmd)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Error sending EHLO.\n");
-#endif
- free(buffer);
- free(smtpcode);
- return(SOCKET_ERROR);
- }
-
- /* Processing SMTP server reply */
- memset(buffer,0,BUFFER_LENGTH);
- if(!read_to(sdesc,rfds,tv,buffer)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Error receiving data from smtp server.\n");
-#endif
- free(buffer);
- free(smtpcode);
- return(SOCKET_ERROR);
- }
- /* Look for response code */
- memset(smtpcode,0,SMTP_ERROR_CODE_LENGTH);
- memcpy(smtpcode,buffer,SMTP_ERROR_CODE_LENGTH-1);
- if(strcmp(smtpcode,retcode) != 0) {
-#ifdef DEBUG
- logmessage(buffer);
-#endif
- free(buffer);
- free(smtpcode);
- return(SOCKET_ERROR);
- }
-
- free(buffer);
- free(smtpcode);
- return(SOCKET_SUCCESS);
-}
-
-int SMTP_SENDMAIL(char *IP_DST, char *PORT_DST, char *from, char *to,char *subject,char *body,int ctimeout)
-{
- register int sdesc;
- int long_inet;
- struct hostent *ip_serv;
- struct sockaddr_in adr_serv;
- struct linger li = { 0 };
- char *debugmsg;
- char *buffer;
- char *smtpcode;
- char *smtpcmd;
- struct timeval tv;
- fd_set rfds, wfds;
- int rc, flags;
- int arglen;
-
- debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
- buffer=(char *)malloc(BUFFER_LENGTH);
- smtpcode=(char *)malloc(SMTP_ERROR_CODE_LENGTH);
- smtpcmd=(char *)malloc(SMTP_CMD_LENGTH);
- memset(buffer,0,BUFFER_LENGTH);
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- memset(smtpcode,0,SMTP_ERROR_CODE_LENGTH);
- memset(smtpcmd,0,SMTP_CMD_LENGTH);
-
- if ( (sdesc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"SMTP_SENDMAIL : Can not bind remote address %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- free(debugmsg);
- free(buffer);
- return(SOCKET_ERROR);
- }
-
- /* free the tcp port after closing the socket descriptor */
- li.l_onoff=1;
- li.l_linger=0;
- setsockopt(sdesc,SOL_SOCKET,SO_LINGER,(char *)&li,sizeof(struct linger));
-
- long_inet = sizeof(struct sockaddr_in);
-
- if ( (ip_serv=gethostbyname(IP_DST)) == NULL) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"SMTP_SENDMAIL : Can not resolve remote host %s\n",IP_DST);
- logmessage(debugmsg);
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- memset(&adr_serv,0,long_inet);
- adr_serv.sin_family=ip_serv->h_addrtype;
- bcopy(ip_serv->h_addr, &adr_serv.sin_addr.s_addr,ip_serv->h_length);
- adr_serv.sin_port=htons(atoi(PORT_DST));
-
- /* Set read/write socket timeout */
- flags=fcntl(sdesc, F_GETFL);
- fcntl(sdesc, F_SETFL, flags | O_NONBLOCK);
-
- /* Connect the remote host */
- if ( (rc=connect(sdesc, (struct sockaddr *)&adr_serv, long_inet)) == -1) {
- switch (errno) {
- case ETIMEDOUT:
- case EINTR:
- case EHOSTUNREACH:
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"SMTP_SENDMAIL : Connection timeout to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- break;
- case ECONNREFUSED:
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"SMTP_SENDMAIL : Connection refused to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- break;
- case ENETUNREACH:
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"SMTP_SENDMAIL : Network unreachable to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- break;
- case EINPROGRESS: // NONBLOCK socket connection in progress
- goto next;
- default:
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"SMTP_SENDMAIL : Network error [%s] to %s:%s\n",strerror(errno),IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- }
-
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
-next:
- /* Timeout settings */
- tv.tv_sec=ctimeout;
- tv.tv_usec=0;
- FD_ZERO(&rfds);
- FD_ZERO(&wfds);
- FD_SET(sdesc,&rfds);
- FD_SET(sdesc,&wfds);
-
- rc = select(sdesc+1,&rfds,NULL,NULL,&tv);
- if (!FD_ISSET(sdesc,&rfds)) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"SMTP_SENDMAIL : Timeout reading data to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- if (rc < 0) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"SMTP_SENDMAIL : Select returned descriptor error to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- rc = 0;
- arglen=sizeof(int);
- if (getsockopt(sdesc,SOL_SOCKET,SO_ERROR,&rc,&arglen) < 0)
- rc = errno;
-
- if (rc) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"SMTP_SENDMAIL : Connection failed to %s:%s (%s)\n",IP_DST,PORT_DST,strerror(rc));
- logmessage(debugmsg);
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- /* Proceed the SMTP server reply */
- if(!read_to(sdesc,rfds,tv,buffer)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Error receiving data from smtp server.\n");
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- /* Look for connect code */
- memset(smtpcode,0,SMTP_ERROR_CODE_LENGTH);
- memcpy(smtpcode,buffer,SMTP_ERROR_CODE_LENGTH-1);
- if(strcmp(smtpcode,SMTP_CONNECT) != 0) {
-#ifdef DEBUG
- logmessage("Can not connect remote smtp server.\n");
-#endif
- }
-
- /* Sending host identification */
- memset(buffer,0,BUFFER_LENGTH);
- if(gethostname(buffer,500)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Error resolving local hostname\n");
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- /* Sending EHLO command to remote smtp server */
- memset(smtpcmd,0,SMTP_CMD_LENGTH);
- sprintf(smtpcmd,"EHLO %s\n",buffer);
- if(!smtp_cmd(sdesc,wfds,rfds,tv,smtpcmd,SMTP_EHLO)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Error sending EHLO.\n");
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- /* Sending MAIL FROM command to remote smtp server */
- memset(smtpcmd,0,SMTP_CMD_LENGTH);
- sprintf(smtpcmd,"MAIL FROM:%s\n",from);
- if(!smtp_cmd(sdesc,wfds,rfds,tv,smtpcmd,SMTP_MAIL_FROM)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Error sending MAIL FROM.\n");
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- /* Sending RCPT TO command to remote smtp server */
- memset(smtpcmd,0,SMTP_CMD_LENGTH);
- sprintf(smtpcmd,"RCPT TO:%s\n",to);
- if(!smtp_cmd(sdesc,wfds,rfds,tv,smtpcmd,SMTP_RCPT_TO)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Error sending RCPT TO.\n");
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- /* Sending DATA command to remote smtp server */
- memset(smtpcmd,0,SMTP_CMD_LENGTH);
- sprintf(smtpcmd,"DATA\n");
- if(!smtp_cmd(sdesc,wfds,rfds,tv,smtpcmd,SMTP_DATA)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Error sending DATA.\n");
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- /* Sending smtp header to remote smtp server */
- memset(smtpcmd,0,SMTP_CMD_LENGTH);
- sprintf(smtpcmd,"Subject: %s\nX-Mailer: Keepalived SmtpWrapper\n\n",subject);
- if(!send_to(sdesc,wfds,tv,smtpcmd)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Error sending smtp header.\n");
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- /* Sending smtp body to remote smtp server */
- memset(smtpcmd,0,SMTP_CMD_LENGTH);
- sprintf(smtpcmd,"\n\n%s\n\n",body);
- if(!send_to(sdesc,wfds,tv,smtpcmd)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Error sending smtp body.\n");
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- /* Sending DATA command to remote smtp server */
- memset(smtpcmd,0,SMTP_CMD_LENGTH);
- sprintf(smtpcmd,"\n.\n");
- if(!smtp_cmd(sdesc,wfds,rfds,tv,smtpcmd,SMTP_DOT)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Error sending trailing DOT.\n");
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- /* Sending quit to remote smtp server */
- memset(smtpcmd,0,SMTP_CMD_LENGTH);
- sprintf(smtpcmd,"QUIT\n",body);
- if(!send_to(sdesc,wfds,tv,smtpcmd)) {
-#ifdef DEBUG
- logmessage("SMTP_SENDMAIL : Error sending smtp quit.\n");
-#endif
- free(debugmsg);
- free(buffer);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- close(sdesc);
- free(debugmsg);
- free(buffer);
- return(SOCKET_SUCCESS);
-}
-
-void SMTP_SEND_ALERTES(configuration_data *lstconf,virtualserver *lstvs,char *subject,char *body)
-{
- char *tmpbuff;
- char *debugmsg;
- notification_email *pointeremail;
-
- tmpbuff=(char *)malloc(500);
- debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
- memset(tmpbuff,0,500);
-
- sprintf(tmpbuff,"[%s] %s:%s - %s",lstconf->lvs_id,lstvs->svr->addr_ip,lstvs->svr->addr_port,subject);
-
- pointeremail=lstconf->email;
- while(lstconf->email != NULL) {
- if(!SMTP_SENDMAIL(lstconf->smtp_server,SMTP_PORT,lstconf->email_from,lstconf->email->addr,tmpbuff,body,6)) {
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"SMTP_SEND_ALERTES : Can not send alerte to %s.\n",lstconf->email->addr);
- logmessage(debugmsg);
- }
- lstconf->email=(notification_email *)lstconf->email->next;
- }
- lstconf->email=pointeremail;
-
- free(tmpbuff);
- free(debugmsg);
-}
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: smtpwrapper.c include file.
- *
- * Version: $Id: smtpwrapper.h,v 0.2.6 2001/03/01 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef SMTPWRAPPER_H
-#define SMTPWRAPPER_H
-
-#include <signal.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <fcntl.h>
-#include <errno.h>
-#include "cfreader.h"
-
-#define SOCKET_ERROR 0
-#define SOCKET_SUCCESS 1
-#define SOCKET_TIMEOUT 3
-
-#define SMTP_PORT "25"
-
-#define SMTP_CONNECT "220"
-#define SMTP_EHLO "250"
-#define SMTP_MAIL_FROM "250"
-#define SMTP_RCPT_TO "250"
-#define SMTP_DATA "354"
-#define SMTP_DOT "250"
-
-
-#define LOGBUFFER_LENGTH 100
-#define BUFFER_LENGTH 1024
-#define SMTP_ERROR_CODE_LENGTH 4
-#define SMTP_CMD_LENGTH 500
-
-#endif
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: TCP CHECK. Build a TCP/IP packet and send it to a remote
- * server. This check implement the tcp half open connection
- * check.
- *
- * Version: $Id: tcpcheck.c,v 0.2.7 2001/03/27 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : 2001/03/27 :
- * <+> Close the socket descriptor missing !
- * causing a prematurely daemon daemon hangup. (oops)
- *
- * Alexandre Cassen : 2001/02/16 :
- * <-> Suppress the whole RAW_SOCKET tcpcheck level initial implementation.
- * <+> Replace the RAW_SOCKET initial implementation by a vanilla tcpcheck.
- * Using non blocking & no_linger socket. Use a timeval to set socket
- * descriptor timeout.
- *
- * Alexandre Cassen : 2000/12/29 :
- * <+> Added recvfrom_to() function to handle recvfrom timeouted connection.
- * Call this function in TCP_RCV_SYNACK_PACKET with 1s timeout.
- * <+> Added a timer (2s timeouted) in TCP_RCV_SYNACK_PACKET to check
- * SYN|ACK packet. Check perform on tcp sequence, remote tcp port number,
- * tcp SYN|ACK flag, remote ip address.
- * <+> Added a 3 time SYN packet send retry.
- *
- * Alexandre Cassen : 2000/12/09 : Initial release
- *
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#include "tcpcheck.h"
-
-int TCP_CHECK(const char *IP_DST, const char *PORT_DST)
-{
- register int sdesc;
- int long_inet;
- char *debugmsg;
- struct hostent *ip_serv;
- struct sockaddr_in adr_serv;
- struct linger li = { 0 };
- struct timeval tv;
- fd_set wfds;
- int rc, val;
- int arglen;
-
- /* Memory allocation for the data structures */
- debugmsg=(char *)malloc(LOGBUFFER_LENGTH);
- memset(debugmsg,0,LOGBUFFER_LENGTH);
-
- if ( (sdesc = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1 ) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"TCP_CHECK : Can not bind remote address %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- free(debugmsg);
- return(SOCKET_ERROR);
- }
-
- /* free the tcp port after closing the socket descriptor */
- li.l_onoff=1;
- li.l_linger=0;
- setsockopt(sdesc,SOL_SOCKET,SO_LINGER,(char *)&li,sizeof(struct linger));
-
- long_inet = sizeof(struct sockaddr_in);
-
- if ( (ip_serv=gethostbyname(IP_DST)) == NULL) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"TCP_CHECK : Can not resolve remote host %s\n",IP_DST);
- logmessage(debugmsg);
-#endif
- free(debugmsg);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- memset(&adr_serv,0,long_inet);
- adr_serv.sin_family=ip_serv->h_addrtype;
- bcopy(ip_serv->h_addr, &adr_serv.sin_addr.s_addr,ip_serv->h_length);
- adr_serv.sin_port=htons(atoi(PORT_DST));
-
- /* Set read/write socket timeout */
- val=fcntl(sdesc, F_GETFL);
- fcntl(sdesc, F_SETFL, val | O_NONBLOCK);
-
- /* Connect the remote host */
- if ( (rc=connect(sdesc, (struct sockaddr *)&adr_serv, long_inet)) == -1) {
- switch (errno) {
- case ETIMEDOUT:
- case EINTR:
- case EHOSTUNREACH:
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"TCP_CHECK : Connection timeout to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- break;
- case ECONNREFUSED:
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"TCP_CHECK : Connection refused to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- break;
- case ENETUNREACH:
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"TCP_CHECK : Network unreachable to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- break;
- case EINPROGRESS: // NONBLOCK socket connection in progress
- goto next;
- default:
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"TCP_CHECK : Network error [%s] to %s:%s\n",strerror(errno),IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- }
-
- free(debugmsg);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
-next:
- /* Timeout settings */
- tv.tv_sec=SOCKET_TIMEOUT;
- tv.tv_usec=0;
- FD_ZERO(&wfds);
- FD_SET(sdesc,&wfds);
-
- rc = select(sdesc+1,NULL,&wfds,NULL,&tv);
- if (!FD_ISSET(sdesc,&wfds)) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"TCP_CHECK : Timeout writing data to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- free(debugmsg);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- if (rc < 0) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"TCP_CHECK : Select returned descriptor error to %s:%s\n",IP_DST,PORT_DST);
- logmessage(debugmsg);
-#endif
- free(debugmsg);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- rc = 0;
- arglen=sizeof(int);
- if (getsockopt(sdesc,SOL_SOCKET,SO_ERROR,&rc,&arglen) < 0)
- rc = errno;
-
- if (rc) {
-#ifdef DEBUG
- memset(debugmsg,0,LOGBUFFER_LENGTH);
- sprintf(debugmsg,"TCP_CHECK : Connection failed to %s:%s (%s)\n",IP_DST,PORT_DST,strerror(rc));
- logmessage(debugmsg);
-#endif
- free(debugmsg);
- close(sdesc);
- return(SOCKET_ERROR);
- }
-
- close(sdesc);
- free(debugmsg);
- return(SOCKET_SUCCESS);
-}
+++ /dev/null
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: tcpcheck.c include file.
- *
- * Version: $Id: tcpcheck.h,v 0.2.1 2000/12/09 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-#ifndef CFREADER_H
-#define CFREADER_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <signal.h>
-#include <netdb.h>
-#include <netinet/in.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <linux/ip.h>
-#include <linux/tcp.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#define SOCKET_ERROR 0
-#define SOCKET_SUCCESS 1
-#define SOCKET_TIMEOUT 3
-
-
-#define LOGBUFFER_LENGTH 100
-
-/* prototypes */
-//int TCP_CHECK(const char *IP_DST, const char *PORT_DST);
-
-#endif
*
* Part: General program utils.
*
- * Version: $Id: utils.c,v 0.2.1 2000/12/09 $
+ * Version: $Id: utils.c,v 0.3.5 2001/07/13 03:46:38 acassen Exp $
*
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
+ * Author: Alexandre Cassen, <acassen@linux-vs.org>
*
* Changes:
- * Alexandre Cassen : Initial release
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
}
}
-void initdaemonpid(int pid)
-{
- daemonpid=pid;
-}
-
-void logmessage(char *msg)
-{
- FILE *logfile;
- time_t hint;
- struct tm *date;
-
- hint = time((long*)0);
- date = localtime(&hint);
- logfile=fopen(LOGFILE,"ab");
- fprintf(logfile,"[%.2d/%.2d/%.2d - %.2d:%.2d:%.2d] keepalived[%d]: %s",
- date->tm_mday,
- date->tm_mon+1,
- date->tm_year-100,
- date->tm_hour,
- date->tm_min,
- date->tm_sec,
- daemonpid,msg);
- fclose(logfile);
-}
-/*
- * Soft: Keepalived is a failover program for the LVS project
- * <www.linuxvirtualserver.org>. It monitor & manipulate
- * a loadbalanced server pool using multi-layer checks.
- *
- * Part: utils.c include file.
- *
- * Version: $Id: utils.h,v 0.2.1 2000/12/09 $
- *
- * Author: Alexandre Cassen, <Alexandre.Cassen@wanadoo.fr>
- *
- * Changes:
- * Alexandre Cassen : Initial release
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
+#ifndef _UTILES_H
+#define _UTILES_H
-#ifndef UTILS_H
-#define UTILS_H
-
-#include <unistd.h>
-#include <stdlib.h>
+/* system includes */
#include <stdio.h>
-#include <termios.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <netdb.h>
-#include <string.h>
-
-#define LOGFILE "log/keepalived.log"
-/* Globals defs */
-int daemonpid;
+/* Prototypes defs */
+void print_buffer(int count, char *buff);
#endif