./balance-3.57/000075500001440000001000000000001251763562500126505ustar00tother00001460000100./balance-3.57/balance.1000064400001440000001000000223651251763562500143270ustar00tother00001460000100.TH BALANCE 1 "03 Dec 2010" .SH NAME balance 3.54 \- A simple TCP proxy with load balancing and failover mechanisms. .SH SYNOPSIS .B balance [ .B -b addr ] [ .B -B addr ] [ .B -t sec ] [ .B -T sec ] [ .B -adfpHM6 ] port host1[:port1[:maxc]] [!|%] [ ... hostn[:portn[:maxc]]] .PP .B balance [ .B -b addr ] .B -i [ .B -d ] [ .B -M ] port .PP .B balance [ .B -b addr ] .B -c cmd [ .B -d ] [ .B -M ] port .SH DESCRIPTION .I Balance is a simple, generic "userland" TCP proxy, which allows simple round-robin load balancing and graceful failover between several destination servers. .PP .I Balance supports IPv6 on the listening side which makes it a very useful tool for IPv6 migration of IPv4 only services and servers. .PP .I Balance is available at http://balance.sourceforge.net. .PP .I Definitions: A possible destination consisting of a host address and a port is called a "channel". A channel is member of a "channel group". Channels are numbered in a group starting with 0. Groups are numbered starting with 0, which is the initial default group. .PP .I Balance accepts connections on the given port and forwards them to the supplied channels. At least one channel (in the default group) must be specified. If there are two or more channels specified in a group .I balance performs a simple round-robin load balancing between the channels. .PP .I Balance allows the definition of further channel groups. The connection scheme works as follows: .I balance tries first to establish a connection to a channel in the first group (0), performing the standard round-robin load balancing scheme. If no channel in this group is available, .I balance proceeds with the next higher channel group. Groups are simply separated with a "!" at the command line at startup and can be controlled interactively with the "group" command. .PP A "%" instead of a "!" as a group separator declares the previous group to be of type "hash". This means that instead of a round-robin algorithm, a hash distribution based on the client ip address is used to determine the destination channel. This allows connecting one client always to the same server (e.g. balancing http sessions to a single server). .PP Hosts may be specified either by hostname or by IP address. Ports may be specified either by name (as listed in /etc/services) or numerically. If no port is specified in a destination, the destination port defaults to the source port that .I balance controls. .PP .I Balance allows the specification of the maximum number of connections per channel. This parameter can be optionally added after the port specification separated by a colon (":"). If a maximum number of connections is specified a channel will only be used for this maximum number of simultaneous connections. A maxc value of 0 denotes an unlimited number of connections. This is the initial default value of a channel. .PP The maximum number of groups and channels .I balance can handle is specified at compile time and is initially 16 channels in 16 groups. .PP Failover to another destination (a "channel") occurs if the connection is refused on the current channel or if the connect timeout is reached trying to establish a connection. If all possible destinations (channels) currently fail, the client connection to balance is closed. .PP .I Balance accepts the following options: .TP .B 6 Forces to bind on IPv6 socket by setting hints.ai_family to AF_INET6. .TP .B a Enable autodisable option: A channel needs to be manually re-enabled after a failure. .TP .B b Bindhost: .I Balance binds to the specified host (or address) for listen() instead to INADDR_ANY. .TP .B B Bindhost: .I Balance binds to the specified host (or address) for outgoing connections (the connection will be initiated from this address). .TP .B c Command: allows to send a command to the balance master process (see interactive mode) .TP .B d Debug: .I Balance outputs debugging and tracing information messages on stderr. .TP .B H Hashfailover: .I Balance does failover to next node even if hash is used. .TP .B F Foreground: tells .I balance to stay in foreground. This might be useful for testing and debugging since .I balance can be stopped in that mode using ^C (or other interrupt character). .TP .B M Use memory mapping for IPC instead of shared memory .TP .B i Interactive Control: .I Balance connects to the running instance defined by local port and bind address via shared memory and allows to control the behaviour of it using a command line interface. The access permission using this interface are determined by the access restrictions of the shared memory segment in effect. .I help or "?" prints out a short command overview, .I assign allows to change the host_port assignment of a channel (only if disabled), .I create allows to establish a new destination definition (channel) consisting of host and port in the current group, .I disable disables a channel in the current group, .I enable enables a channel again in the current group, .I group changes the current group in interactive mode where all following commands are targeted, .I hash changes the current group to be of type "Hash", .I help prints out online help informations, .I kill shuts down the master process and exits interactive mode, .I maxc sets the maximum number of connection ot the channel (0 means infinite), .I mrtg-bytes prints out the bytes received/sent in MRTG compatible format (intended to be called with -c automatically by MRTG), .I mrtg-conns prints out the total connections in MRTG compatible format (intended to be called with -c automatically by MRTG), .I quit exits the interactive mode, .I reset resets the byte counters of a channel, .I rr changes the current group to be of type "Round Robin", .I show shows an overview and the status of all channels including the incoming and outgoing transfer volume in bytes. The output is sorted by groups. Additionally the current connections (c) and the maximum allowed connections (maxc) are printed, .I version prints out the version and MAXGROUPS and MAXCHANNELS constants at compile time. .TP .B p Packetdump: .I Balance shows all incoming and outgoing data on stdout using a simple always readable external representation of data. This might be useful for debugging and protocol analysis. .TP .B t Connect Timeout: the default timeout trying to establish a connection to any destination can be changed using this option. The default timeout after which a destination is regarded to be currently inaccessible is 5 seconds. .TP .B T Select Timeout: Timeout for select(), default = 0 (never). This feature is currently untested. .PP .SH EXAMPLES .PP .TP .B $ balance smtp host1.test.net host2.test.net Connection to the local SMTP port will be forwarded alterating to the SMTP port on host1 and host2. .I Balance runs automatically in background. .PP .TP .B $ balance -b 2001:DB8::1 80 10.1.1.1 10.1.1.2 .I Balance binds on port 80 of the local IPv6 IP address 2001:DB8::1 and distributes connections to the IPv4 addresses 10.1.1.1 and 10.1.1.2. .PP .TP .B $ balance -b ::ffff:10.1.1.3 80 10.1.1.1 10.1.1.2 .I Balance binds on port 80 of the local IPv4 IP address 10.1.1.3 (provided in IPv6 notation) and distributes connections to the IPv4 addresses 10.1.1.1 and 10.1.1.2. .PP .TP .B $ balance -fp imap mailserver Connections to the local IMAP port will always be forwarded to the host "mailserver". .I Balance stays in foreground and all data is printed in readable format on stdout. .PP .TP .B $ balance -f 8888 host1 10.1.1.1:8000 Connections to the local port 8888 are forwarded alternating to host1, port 8888 and the host 10.1.1.1, port 8000. .I Balance stays in foreground connected to the "controlling tty". .PP .TP .B $ balance imap mailserver1::16 ! mailserver2 Two groups are specified, each containing one channel member. First up to 16 simultaneous connections are forwarded to "mailserver1". As soon as they are consumed, .I balance proceeds with the next group (1) which will consume all remaining connections forwarding them to the imap ort on "mailserver2". .PP .TP .B $ balance pop3 host1 host2 host3 ! failover1 .I Balance does round robin load balancing for the three hosts in the default group 0 for pop3 services. If all three hosts in group 0 fail, all connections are then forwarded to the host "failover1". .PP .TP .B $ balance telnet target.munich.net::1 Here .I balance is used to restrict all connections to exactly one at a time forwarding the telnet port. .PP .TP .B $ balance 8888 localhost::12 ! localhost::4 ! localhost::2 localhost::2 ! localhost:25 This is a simple test, forming 5 groups where balance is self referencing its own services 20 times. This is simply a test which definitely can be tried at home. .SH BUGS In case that .I balance is not able to forward the connection to any destination the inital connection to balance is always first accepted and then closed again immediately. This is not in every case the behaviour that would have been seen directly on the destination host. .SH AUTHOR Thomas Obermair, Inlab Software GmbH (obermair@acm.org) .PP Copyright (c) 2000-2009,2010 by Thomas Obermair (obermair@acm.org) and Inlab Software GmbH (http://www.inlab.de), Gruenwald, Germany. All rights reserved. .PP Balance is released under the GNU GENERAL PUBLIC LICENSE, see the file COPYING in the source code distribution. !|%] [ ... hostn[:portn[:maxc]]] .PP .B balance [ .B -b addr ] .B -i [ .B -d ] [ .B -M ] port .PP .B balance [ .B -b addr ] .B -c cmd [ .B -d ] [ .B -M ] port .SH DESCRIPTION .I Balance is a simple, generic "userland" TCP proxy, which allows simple round-robin load./balance-3.57/balance.pdf000064400001440000001000000230611251763562500147320ustar00tother00001460000100%PDF-1.2 %쏢 5 0 obj <> stream xYnF}Wt+fsI2A2>27={FRl``ꮪ˩Sv'}N?Վ\ nLL)[ag$s!bzݱWnW6t\F{V$I#Qݫ7()Hqa-y*.vyJ^|("#i&le7v3R#DqWl*͒(KiCFOz"{2^'FeݳaFwA"i2^ж v}Z'iU& XEpU-rmz5Ь]{U7 SqF8.A#mӕ>lr;`7PCt#UEj}3Hn4_u{gCֶv57צ$"M Q֧ҔY!fSl! ʩw'΋,2d-|[^!X%{/^ !mQc=K!MMϏ.b}4OXA@M_7pKnB%IV ,)cU![ĹPقJ*HYb b.MAN^CwzwL%M@W/[a`ސ·]{0b>8Ӭ9bVZQXqQp|z΢8Gõ?}GRzQym/ X&[d46q)6Tuy 0'hqbCRVޣTLrԷ-]٭;YCa9:(1 va^g.m]ت$nφEmmt눽HJe]N6P9(3@|U yDVM/PFmr1Ԍ}uNl u4qS8>1.<XBVL:UGU6-HkM \ t3Lj<љgL\&IpfD]tfM8 .ҲCQgIe?vEl`ZW[Dӷu{G9uP1Uj ^1"RG8MߜL }Y8YAkT!LqˆEHiݴ;#l BWWe.X5068T&50jRYk$͎"R*b}M0ޕ}N۫3!F<)0 KG{E׎YE$ڋ`DTA/O-CB,ͦAKif6mD' S+w5c(mPΏ{3<)me NE H؆- C P :Fs!|ochGq:߉P&gy `%1"{:GfCe".117̤bm8".|'psCHIuSClW~wcx=@1Oϰef#+qEжsu,I}'A 41]cCޱK!alraLѡs\֞ FDpCYq(nrS5JA> stream xZn.)dŹvZ  * j9fܐ\)zD_ߙ/"liŹws_e}_/~՞CJ]_ Qn3H>^,~Tˮ/4HH綼(+뫷W_Ea9fђ\ew v}!R,# legJ7sq^$I# \t8+ J+)窆vz1j۹Fv]TAsŧ8Rl ;PzVþL=Ukŝ rTy"u(q υ enZi#EKvnFt?D䔄YB3) &Աb|_m=%_wtH`CLU;gz|YhmU^@/ 0|aVEMBv}s8 GI-z ( g06 4ȩM{:&JQ(V4Tʜk_ =L*k~ -2eTl9¿QjXPC1cfBpV0HK+o8 uSSLvTxYw;ynUz|.(H;L.`M=c h(#(2EQD'.Z"XDBYk#wOe;U޽#jN;HP"p&q:x !xpiBS="MOw +.( NCM?{"ISkcmKfbqt[$$rvi7\ 쭫3!m W*6h!Ogem^3D ze<(ϴSBQa"* !S Rph7rJ0їrʹ%&g" QfAK!ؙgRWWDți& w,tFL.XI<0nn64ӫ @֔nmX ZyQZ4귪N\{yHITl+:A&gY"/ #}3BAy`ra#]MM=S;BLncRC\Gh_cϕ?VP>v-q#Sp>P>4itvNݟj{Ig֊d0x%*NQf30!i4 ȁmhdOqr;!#>][k} ]qO  x4Λly*"K';ցtfΒRk쫲Ԍ^hQtIk WxvLWRe3òg qhi 8eR1Q{< YF$95>]e[f~?Wf{"i60}"ֽ١^8ܜA/V<!C&mz*4/ͪ1, ~/ HE3kj/(a.E>GuEVh,LTu@n4~4lܻ#}~fhy",V94nk.e&V[3ӐI,)M4v T6E i8!,aAFib)|٣sR~vs"{3sJ;2^E %|vػ؆_nQ=,5BjNT S2U4ROW޿}s35BG'*=]ԪxbQMq\j@6̛w8ӽ&EF9Vƈ !nFbKQ`ްs?7Xyh(qSImeA. ^{&9_./H@\+Ps^ڔ8wwM$o$*Mz 8q/HiϵKiir?YlGY4> stream xWS6~_vf!?dt@)G+Jmr+NrAV~(' ?wQ?#lt qa288&38Ie%l3?u%UNfRI%)-FQSq\ߞ]^(hθ4e4̅<۞OpC<)dgx|YKw2Wj M/$di:(9c^U)h4ME ]х-Mk]jRBUdeZ-VnT *Fٲyډ(9x,w8j <ۧƘD2 @DԇY)Ki_x<>݄̂ɐΪmGүYS ?BLyo.KDspԶ vٻNNeɘ5}?Ñ rI-k"*+`73`O{+Xڈٛm PWKgEU*4KhThWDp0*X"}ZsR[vWx֕fjc['8=rޓ{{8pkhi4˙qJΝ<ȘP=3!LoJq1ȰW)0RF .f7] P`*I[0|B6)*"C @:F.ui~I!sTR3c1>0:"!+Zp;+Z1Q ;+5s(ʨE`e 9!~Q:s[4jK[Y莒9?k"Yh'aIgͻx'"-N]r@dcGɟ}'H"PmU^7@L + LǔhY "Pʎ;D;ۖ> /Contents 5 0 R >> endobj 12 0 obj <> /Contents 13 0 R >> endobj 16 0 obj <> /Contents 17 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 12 0 R 16 0 R ] /Count 3 >> endobj 1 0 obj <> endobj 11 0 obj <> endobj 15 0 obj <> endobj 19 0 obj <> endobj 7 0 obj <> endobj 8 0 obj <> endobj 10 0 obj <> endobj 9 0 obj <> endobj 2 0 obj <>endobj xref 0 20 0000000000 65535 f 0000008669 00000 n 0000009145 00000 n 0000008596 00000 n 0000008166 00000 n 0000000015 00000 n 0000003139 00000 n 0000008885 00000 n 0000008951 00000 n 0000009084 00000 n 0000009016 00000 n 0000008717 00000 n 0000008308 00000 n 0000003159 00000 n 0000006341 00000 n 0000008776 00000 n 0000008452 00000 n 0000006362 00000 n 0000008145 00000 n 0000008835 00000 n trailer << /Size 20 /Root 1 0 R /Info 2 0 R /ID [($Mi~)($Mi~)] >> startxref 9256 %%EOF )Yj d(2Ly!YHqc7^磓qLsB2^'FeݳaFwA"i2^ж v}Z'iU& XEpU-rmz5Ь]{U7 SqF8.A#mӕ>lr;`7PCt#UEj}3Hn4_u{gCֶv57צ$"M Q֧ҔY!fSl! ʩw'΋,2d-|[^!X%{/^ !mQc=K!MMϏ.b}./balance-3.57/balance.c000064400001440000001000001436051251763562500144120ustar00tother00001460000100/* * balance - a balancing tcp proxy * $Revision: 3.57 $ * * Copyright (c) 2000-2009,2010 by Thomas Obermair (obermair@acm.org) * and Inlab Software GmbH (info@inlab.de), Gruenwald, Germany. * All rights reserved. * * Thanks to Bernhard Niederhammer for the initial idea and heavy * testing on *big* machines ... * * For license terms, see the file COPYING in this directory. * * This program is dedicated to Richard Stevens... * * 3.57 * MAXGROUPS has been increased to 32 * 3.56 * added out-of-band data handling * thanks to Julian Griffiths * 3.54 * fixed hash_fold bug regarding incoming IPv4 and IPv6 source addresses * 3.52 * thanks to David J. Jilk from Standing Cloud, Inc. for the following: * added "nobuffer" functionality to interactive shell IO * added new "assign" interactive command * fixed locking bug * 3.50 * new option -6 forces IPv6 bind (hints.ai_family = AF_INET6) * 3.49 * ftok() patch applied (thanks to Vladan Djeric) * 3.48 * Problems with setting IPV6_V6ONLY socket option are now handled * more nicely with a syslog warning message * 3.42 * Balance compiles now on systems where IPV6_V6ONLY is undefined * 3.35 * bugfix in autodisable code (thanks to Michael Durket) * 3.34 * syslog logging added (finally) * -a autodisable option added (thanks to Mitsuru IWASAKI) * 3.33 * SO_KEEPALIVE switched on (suggested and implemented by A. Fluegel) * new option -M to use a memory mapped file instead of IPC shared memory * 3.32 * /var/run/balance may already exist (thanks to Thomas Steudten) * 3.31 * TCP_NODELAY properly switched on (thanks to Kurt J. Lidl). * 3.30 * Code cleanups and fixes (thanks to Kurt J. Lidl) * 3.28 * Code cleanup's (thanks to Thomas Steudten) * MRTG-Interface (thanks to Brian McCann for the suggestion) * 3.26 * bugfix: master process was not found with balance -i * unused variable pid removed (BSD) * 3.24 * bugfix in channel/group argument parsing (thanks to Enrique G. Paredes) * permisions+error messages improvements (thanks to Wojciech Sobczuk) * 3.22 * writelock and channelcount patch from Stoyan Genov * balance exit codes fix from Chris Wilson * /var/run/balance is tried to be autocreated (if not there) * close of 0,1,2 on background operation * 3.19 * -h changed to -H * 3.17 * -h option added * thanks to Werner Maier * 3.16 * fixed missing save_tmout initialization * thanks to Eric Andresen * 3.15 * first -B support * 3.14 * -Wall cleanup * 3.12 * alarm(0) added, thanks to Jon Christensen * 3.11 * Bugfix * 3.10 * Bugfix for RedHat 7.2 * 3.9 * Moved rendezvous file to /var/run and cleaned main(), thanks to * Kayne Naughton * 3.8 * move to sigaction(), thanks to Kayne Naughton * 3.5 * Select-Timeout, thanks to Jeff Buhlmann * 3.2 * Hash groups and some other improvements * 2.24: * 'channel 2 overload' problem fixed, thanks to Ed "KuroiNeko" * 2.26: * 'endless loop error' fixed, thanks to Anthony Baxter * 2.27: * strcmp on NULL removed, thanks to Jay. D. Allen * 2.28: * bsent and breceived now unsigned to avoid negative values, * thanks to Anthony Baxter * 2.29: * error in setaddress() fixed, thanks to Dirk Datzert * 2.30: * fixing #includes for *bsd compability * 2.31: * 2.32: * redefied SIGCHLD handling to be compatible with FreeBSD 4.3, * BSD/OS 4.2 and BSD/OS 4.0.1 * 2.33 * finally included SO_REUSEADDR * */ #include const char *balance_rcsid = "$Id: balance.c,v 3.57 2015/04/28 07:49:16 t Exp $"; static char *revision = "$Revision: 3.57 $"; static int release; static int subrelease; static char rendezvousfile[FILENAMELEN]; static int rendezvousfd; #ifndef NO_MMAP static int shmfilefd; #endif static int cur_s; static int cur_r; static void urg_handler(int signo) { int n; char buf[256]; n = recv(cur_r,buf,sizeof buf,MSG_OOB); if ( n < 0 ) { //printf("ERROR: recv(2)\n"); }else{ buf[n] = 0; //printf("URG '%s' (%d)\n", buf,n); send(cur_s, buf,strlen(buf),MSG_OOB); } signal(SIGURG, urg_handler); } static int err_dump(char *text) { fprintf(stderr, "balance: %s\n", text); fflush(stderr); exit(EX_UNAVAILABLE); } COMMON *common; static int hashfailover = 0; static int autodisable = 0; static int debugflag = 0; static int foreground = 0; static int packetdump = 0; static int interactive = 0; static int shmmapfile = 0; static int bindipv6 = 0; static int sockbufsize = 32768; static int connect_timeout; static char *bindhost = NULL; static char *outbindhost = NULL; static struct timeval sel_tmout = { 0, 0 }; /* seconds, microseconds */ static struct timeval save_tmout = { 0, 0 }; /* seconds, microseconds */ int create_serversocket(char* node, char* service) { struct addrinfo hints; struct addrinfo *results; int srv_socket, status, sockopton, sockoptoff; bzero(&hints, sizeof(hints)); hints.ai_flags = AI_PASSIVE; if(bindipv6) { if(debugflag) { fprintf(stderr, "using AF_INET6\n"); } hints.ai_family = AF_INET6; } else { if(debugflag) { fprintf(stderr, "using AF_UNSPEC\n"); } hints.ai_family = AF_UNSPEC; } hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; status = getaddrinfo(node, service, &hints, &results); if(status != 0) { fprintf(stderr,"error at getaddrinfo: %s\n", gai_strerror(status)); fprintf(stderr,"exiting.\n"); exit(EX_OSERR); } if(results == NULL) { fprintf(stderr,"no matching results at getaddrinfo\n"); fprintf(stderr,"exiting.\n"); exit(EX_OSERR); } srv_socket = socket(results->ai_family, results->ai_socktype, results->ai_protocol); if(srv_socket < 0) { perror("socket()"); exit(EX_OSERR); } sockoptoff = 0; #if defined(IPV6_V6ONLY) status = setsockopt(srv_socket, IPPROTO_IPV6, IPV6_V6ONLY, (char*) &sockoptoff, sizeof(sockoptoff)); if(status < 0) { syslog(LOG_WARNING,"setsockopt(IPV6_V6ONLY=0) failed"); } #endif sockopton = 1; status = setsockopt(srv_socket, SOL_SOCKET, SO_REUSEADDR, (char*) &sockopton, sizeof(sockopton)); if(status < 0) { perror("setsockopt(SO_REUSEADDR=1)"); exit(EX_OSERR); } status = bind(srv_socket, results->ai_addr, results->ai_addrlen); if(status < 0) { perror("bind()"); exit(EX_OSERR); } status = listen(srv_socket, SOMAXCONN); if(status < 0) { perror("listen()"); exit(EX_OSERR); } return(srv_socket); } /* locking ... */ int a_readlock(off_t start, off_t len) { int rc; struct flock fdata; fdata.l_type = F_RDLCK; fdata.l_whence = SEEK_SET; fdata.l_start = 0; fdata.l_len = 0; // fdata.l_sysid=0; // fdata.l_pid=0; repeat: if ((rc = fcntl(rendezvousfd, F_SETLKW, &fdata)) < 0) { if (errno == EINTR) { goto repeat; // 8-) } else { perror("readlock"); exit(EX_OSERR); } } return (rc); } void b_readlock(void) { a_readlock(0, 0); } void c_readlock(int group, int channel) { a_readlock(((char *) &(grp_channel(common, group, channel))) - (char *) common, sizeof(CHANNEL)); } int a_writelock(off_t start, off_t len) { int rc; struct flock fdata; fdata.l_type = F_WRLCK; fdata.l_whence = SEEK_SET; fdata.l_start = 0; fdata.l_len = 0; // fdata.l_sysid=0; // fdata.l_pid=0; repeat: if ((rc = fcntl(rendezvousfd, F_SETLKW, &fdata)) < 0) { if (errno == EINTR) { goto repeat; // 8-) } else { perror("a_writelock"); exit(EX_OSERR); } } return (rc); } void b_writelock(void) { a_writelock(0, 0); } void c_writelock(int group, int channel) { a_writelock(((char *) &(grp_channel(common, group, channel))) - (char *) common, sizeof(CHANNEL)); } int a_unlock(off_t start, off_t len) { int rc; struct flock fdata; fdata.l_type = F_UNLCK; fdata.l_whence = SEEK_SET; fdata.l_start = 0; fdata.l_len = 0; // fdata.l_sysid=0; // fdata.l_pid=0; repeat: if ((rc = fcntl(rendezvousfd, F_SETLK, &fdata)) < 0) { if (errno == EINTR) { goto repeat; // 8-) } else { perror("a_unlock"); exit(EX_OSERR); } } return (rc); } void b_unlock(void) { a_unlock(0, 0); } void c_unlock(int group, int channel) { a_unlock(((char *) &(grp_channel(common, group, channel))) - (char *) common, sizeof(CHANNEL)); } void *shm_malloc(char *file, int size) { char *data = NULL; key_t key; int shmid; if(shmmapfile){ #ifndef NO_MMAP char shmfile[FILENAMELEN]; strcpy(shmfile, file); strcat(shmfile, SHMFILESUFFIX); shmfilefd = open(shmfile, O_RDWR | O_CREAT, 0644); if(shmfilefd < 0) { fprintf(stderr, "Warning: Cannot open file `%s', switching to IPC\n", shmfile); shmmapfile = 0; } if(shmmapfile) { if(ftruncate(shmfilefd, size) < 0) { fprintf(stderr, "Warning: Cannot set file size on `%s', switching to IPC\n", shmfile); close(shmfilefd); shmmapfile = 0; } } if(shmmapfile) { data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, shmfilefd, 0); if(!data || data == MAP_FAILED) { fprintf(stderr, "Warning: Cannot map file `%s', switching to IPC\n", shmfile); close(shmfilefd); shmmapfile = 0; } } #endif } if(!shmmapfile){ #if defined (__SVR4) && defined (__sun) /* vdjeric: Solaris ftok() causes frequent collisions because it uses only the lower 12 bits of the inode number in the 'key'. See: http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=4265917 */ FILE *rendezvousfp = NULL; struct timeval ct; long int seed; int i; if ((rendezvousfp = fdopen(rendezvousfd, "w+")) == NULL) { perror("fdopen"); exit(EX_OSERR); } if ((fscanf(rendezvousfp, "0x%x\n", &key)) <= 0) { gettimeofday(&ct, NULL); seed = ct.tv_usec * getpid(); srand(seed); /* Solaris rand() returns values between 0 and 0x7fff, so generate key byte by byte */ key = 0; for (i = 0; i < sizeof(key); i++) { key = (key << 8) | (rand() & 0xff); } if(fseek(rendezvousfp, 0, SEEK_SET) == -1) { perror("fseek"); exit(EX_OSERR); } if (fprintf(rendezvousfp, "0x%08x\n", key) == -1) { perror("fprintf"); exit(EX_OSERR); } fflush(rendezvousfp); } #else if ((key = ftok(file, 'x')) == -1) { perror("ftok"); exit(EX_SOFTWARE); } #endif if ((shmid = shmget(key, size, 0644 | IPC_CREAT)) == -1) { perror("shmget"); exit(EX_OSERR); } data = shmat(shmid, (void *) 0, 0); if (data == (char *) (-1)) { perror("shmat"); exit(EX_OSERR); } } return (data); } /* readable output of a packet (-p) */ void print_packet(unsigned char *s, int l) { int i, cc; cc = 0; for (i = 0; i < l; i++) { if (isprint(s[i]) && isascii(s[i])) { if (s[i] == '\\') { printf("\\\\"); cc += 2; } else { printf("%c", s[i]); cc++; } } else { printf("\\%02X", s[i]); cc += 3; if (s[i] == '\n') { printf("\n"); cc = 0; } } if (cc > 80) { printf("\n"); cc = 0; } } printf("\n"); } int getport(char *port) { struct servent *sp; sp = getservbyname(port, "tcp"); if (sp == NULL) { return (atoi(port)); } else { return (ntohs(sp->s_port)); } } void setipaddress(struct in_addr *ipaddr, char *string) { struct hostent *hent; hent = gethostbyname(string); if (hent == NULL) { if ((ipaddr->s_addr = inet_addr(string)) == INADDR_NONE) { fprintf(stderr, "unknown or invalid address [%s]\n", string); exit(EX_DATAERR); } } else { memcpy(ipaddr, hent->h_addr, hent->h_length); } } void setaddress(struct in_addr *ipaddr, int *port, char *string, int default_port, int *maxc) { char *host_string = NULL; char *port_string = NULL; char *maxc_string = NULL; char *dup_string = NULL; char *p = NULL; char *q = NULL; struct hostent *hent; if ((dup_string = strdup(string)) == NULL) { fprintf(stderr, "strdup() failed\n"); exit(EX_OSERR); } host_string = dup_string; p = index(dup_string, ':'); if (p != NULL) { *p = '\000'; port_string = p + 1; if ((q = index(port_string, ':')) != NULL) { *q = '\000'; maxc_string = q + 1; } else { maxc_string = ""; } } else { port_string = ""; maxc_string = ""; } // fix for RedHat 7.0/7.1 choke on strcmp with NULL if (port_string != NULL && !strcmp(port_string, "")) port_string = NULL; if (maxc_string != NULL && !strcmp(maxc_string, "")) maxc_string = NULL; hent = gethostbyname(dup_string); if (hent == NULL) { if ((ipaddr->s_addr = inet_addr(dup_string)) == INADDR_NONE) { fprintf(stderr, "unknown or invalid address [%s]\n", dup_string); exit(EX_DATAERR); } } else { memcpy(ipaddr, hent->h_addr, hent->h_length); } if (port_string != NULL) { *port = getport(port_string); } else { *port = default_port; } if (maxc_string != NULL) { *maxc = atoi(maxc_string); } free(dup_string); } int setaddress_noexitonerror(struct in_addr *ipaddr, int *port, char *string, int default_port) { char *host_string; char *port_string; struct hostent *hent; host_string = strtok(string, ":"); port_string = strtok(NULL, ":"); hent = gethostbyname(string); if (hent == NULL) { if ((ipaddr->s_addr = inet_addr(string)) == INADDR_NONE) { return (0); } } else { memcpy(ipaddr, hent->h_addr, hent->h_length); } if (port_string != NULL) { *port = getport(port_string); } else { *port = default_port; } return (1); } int readline(int fd, char *ptr, int maxlen) { int n, rc; char c; for (n = 1; n < maxlen; n++) { if ((rc = read(fd, &c, 1)) == 1) { *ptr++ = c; if (c == '\n') { break; } } else if (rc == 0) { if (n == 1) { return (0); // EOF, no data read } else { break; // EOF, some data was read } } else { return (-1); // error } } *ptr = 0; return (n); } int forward(int fromfd, int tofd, int groupindex, int channelindex) { ssize_t rc; unsigned char buffer[MAXTXSIZE]; cur_s = tofd; cur_r = fromfd; /* struct sigaction urg_action; urg_action.sa_handler = urg_handler; urg_action.sa_flags = SA_RESTART; sigemptyset(&urg_action.sa_mask); sigaction(SIGURG, &urg_action, NULL); */ signal(SIGURG, &urg_handler); //rc = read(fromfd, buffer, MAXTXSIZE); fcntl(fromfd, F_SETOWN,getpid()); rc = recv(fromfd, buffer, MAXTXSIZE, 0); if (packetdump) { printf("-> %d\n", (int) rc); print_packet(buffer, rc); } if (rc <= 0) { return (-1); } else { if (writen(tofd, buffer, rc) != rc) { return (-1); } c_writelock(groupindex, channelindex); chn_bsent(common, groupindex, channelindex) += rc; c_unlock(groupindex, channelindex); } return (0); } int backward(int fromfd, int tofd, int groupindex, int channelindex) { ssize_t rc; unsigned char buffer[MAXTXSIZE]; rc = read(fromfd, buffer, MAXTXSIZE); if (packetdump) { printf("-< %d\n", (int) rc); print_packet(buffer, rc); } if (rc <= 0) { return (-1); } else { if (writen(tofd, buffer, rc) != rc) { return (-1); } c_writelock(groupindex, channelindex); chn_breceived(common, groupindex, channelindex) += rc; c_unlock(groupindex, channelindex); } return (0); } /* * the connection is really established, let's transfer the data * as efficient as possible :-) */ void stream2(int clientfd, int serverfd, int groupindex, int channelindex) { fd_set readfds; int fdset_width; int sr; int optone = 1; fdset_width = ((clientfd > serverfd) ? clientfd : serverfd) + 1; /* failure is acceptable */ (void) setsockopt(serverfd, IPPROTO_TCP, TCP_NODELAY, (char *)&optone, (socklen_t)sizeof(optone)); (void) setsockopt(clientfd, IPPROTO_TCP, TCP_NODELAY, (char *)&optone, (socklen_t)sizeof(optone)); (void) setsockopt(serverfd, SOL_SOCKET, SO_KEEPALIVE, (char *)&optone, (socklen_t)sizeof(optone)); (void) setsockopt(clientfd, SOL_SOCKET, SO_KEEPALIVE, (char *)&optone, (socklen_t)sizeof(optone)); for (;;) { FD_ZERO(&readfds); FD_SET(clientfd, &readfds); FD_SET(serverfd, &readfds); /* * just in case this system modifies the timeout values, * refresh the values from a saved copy of them. */ sel_tmout = save_tmout; for (;;) { if (sel_tmout.tv_sec || sel_tmout.tv_usec) { sr = select(fdset_width, &readfds, NULL, NULL, &sel_tmout); } else { sr = select(fdset_width, &readfds, NULL, NULL, NULL); } if ((save_tmout.tv_sec || save_tmout.tv_usec) && !sr) { c_writelock(groupindex, channelindex); chn_c(common, groupindex, channelindex) -= 1; c_unlock(groupindex, channelindex); fprintf(stderr, "timed out after %d seconds\n", (int) save_tmout.tv_sec); exit(EX_UNAVAILABLE); } if (sr < 0 && errno != EINTR) { c_writelock(groupindex, channelindex); chn_c(common, groupindex, channelindex) -= 1; c_unlock(groupindex, channelindex); err_dump("select error"); } if (sr > 0) break; } if (FD_ISSET(clientfd, &readfds)) { if (forward(clientfd, serverfd, groupindex, channelindex) < 0) { break; } } else { if (backward(serverfd, clientfd, groupindex, channelindex) < 0) { break; } } } c_writelock(groupindex, channelindex); chn_c(common, groupindex, channelindex) -= 1; c_unlock(groupindex, channelindex); exit(EX_OK); } void alrm_handler(int signo) { } void usr1_handler(int signo) { } void chld_handler(int signo) { int status; while (waitpid(-1, &status, WNOHANG) > 0); } /* * a channel in a group is selected and we try to establish a connection */ void *stream(int arg, int groupindex, int index, char *client_address, int client_address_size) { int startindex; int sockfd; int clientfd; struct sigaction alrm_action; struct sockaddr_in serv_addr; startindex = index; // lets keep where we start... clientfd = arg; for (;;) { if (debugflag) { fprintf(stderr, "trying group %d channel %d ... ", groupindex, index); fflush(stderr); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0) { err_dump("can't open stream socket"); } (void) setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sockbufsize, sizeof(sockbufsize)); (void) setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &sockbufsize, sizeof(sockbufsize)); /* * if -B is specified, balance tries to bind to it even on * outgoing connections */ if (outbindhost != NULL) { struct sockaddr_in outbind_addr; bzero((char *) &outbind_addr, sizeof(outbind_addr)); outbind_addr.sin_family = AF_INET; setipaddress(&outbind_addr.sin_addr, outbindhost); if (bind (sockfd, (struct sockaddr *) &outbind_addr, sizeof(outbind_addr)) < 0) { } } b_readlock(); bzero((char *) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = chn_ipaddr(common, groupindex, index).s_addr; serv_addr.sin_port = htons(chn_port(common, groupindex, index)); b_unlock(); alrm_action.sa_handler = alrm_handler; alrm_action.sa_flags = 0; // don't restart ! sigemptyset(&alrm_action.sa_mask); sigaction(SIGALRM, &alrm_action, NULL); alarm(connect_timeout); if (connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { if (debugflag) { if (errno == EINTR) { fprintf(stderr, "timeout group %d channel %d\n", groupindex, index); } else { fprintf(stderr, "connection refused group %d channel %d\n", groupindex, index); } } /* here we've received an error (either 'timeout' or 'connection refused') * let's start some magical failover mechanisms */ c_writelock(groupindex, index); chn_c(common, groupindex, index)--; if(autodisable) { if(chn_status(common, groupindex, index) != 0) { if(foreground) { fprintf(stderr, "connection failed group %d channel %d\n", groupindex, index); fprintf(stderr, "%s:%d needs to be enabled manually using balance -i after the problem is solved\n", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port)); } else { syslog(LOG_NOTICE,"connection failed group %d channel %d", groupindex, index); syslog(LOG_NOTICE,"%s:%d needs to be enabled manually using balance -i after the problem is solved", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port)); } chn_status(common, groupindex, index) = 0; } } c_unlock(groupindex, index); b_readlock(); for (;;) { for (;;) { if (grp_type(common, groupindex) == GROUP_RR || hashfailover == 1) { index++; if (index >= grp_nchannels(common, groupindex)) { index = 0; } if (index == startindex) { index = -1; // Giveup break; } if (chn_status(common, groupindex, index) == 1 && (chn_maxc(common, groupindex, index) == 0 || (chn_c(common, groupindex, index) < chn_maxc(common, groupindex, index)))) { break; // new index found } else { continue; } } else if (grp_type(common, groupindex) == GROUP_HASH) { // If the current group is type hash, we giveup immediately index = -1; break; } else { err_dump("PANIC: invalid group in stream()"); } } if (index >= 0) { // neuer index in groupindex-group found... break; } else { again: groupindex++; if (groupindex >= MAXGROUPS) { // giveup, index=-1. break; } else { if (grp_type(common, groupindex) == GROUP_RR) { if (grp_nchannels(common, groupindex) > 0) { index = grp_current(common, groupindex); startindex = index; // This fixes the "endless loop error" // with all hosts being down and one // in the last group... (from Anthony Baxter) } else { goto again; } break; } else if (grp_type(common, groupindex) == GROUP_HASH) { unsigned int uindex; uindex = hash_fold((unsigned char*) &(((struct sockaddr_in6 *) &client_address)->sin6_addr), client_address_size); if (debugflag) { fprintf(stderr, "HASH-method: fold returns %u\n", uindex); } index = uindex % grp_nchannels(common, groupindex); if (debugflag) fprintf(stderr, "modulo %d gives %d\n", grp_nchannels(common, groupindex), index); if (chn_status(common, groupindex, index) == 1 && (chn_maxc(common, groupindex, index) == 0 || (chn_c(common, groupindex, index) < chn_maxc(common, groupindex, index))) ) { break; } else { goto again; // next group ! } } else { err_dump("PANIC: invalid group in stream()"); } } } } // we drop out here with a new index b_unlock(); if (index >= 0) { // lets try it again close(sockfd); c_writelock(groupindex, index); chn_c(common, groupindex, index) += 1; chn_tc(common, groupindex, index) += 1; c_unlock(groupindex, index); continue; } else { break; } } else { alarm(0); // Cancel the alarm since we successfully connected if (debugflag) { fprintf(stderr, "connect to channel %d successful\n", index); } // this prevents the 'channel 2 overload problem' b_writelock(); grp_current(common, groupindex) = index; grp_current(common, groupindex)++; if (grp_current(common, groupindex) >= grp_nchannels(common, groupindex)) { grp_current(common, groupindex) = 0; } b_unlock(); // everything's fine ... stream2(clientfd, sockfd, groupindex, index); // stream2 bekommt den Channel-Index mit // stream2 never returns, but just in case... break; } } close(sockfd); exit(EX_OK); } static void initialize_release_variables(void) { char *version; char *revision_copy; char *token; if ((revision_copy = (char *) malloc(strlen(revision) + 1)) == NULL) { fprintf(stderr, "malloc problem in initialize_release_variables()\n"); } else { strcpy(revision_copy, revision); token = strtok(revision_copy, " "); token = strtok(NULL, " "); version = token != NULL ? token : "0.0"; release = atoi(version); if (strlen(version) >= 3) { subrelease = atoi(version + 2); } else { subrelease = 0; } free(revision_copy); } } static void usage(void) { fprintf(stderr," _ _\n"); fprintf(stderr,"| |__ __ _| | __ _ _ __ ___ ___\n"); fprintf(stderr,"| '_ \\ / _` | |/ _` | '_ \\ / __/ _ \\\n"); fprintf(stderr,"| |_) | (_| | | (_| | | | | (_| __/\n"); fprintf(stderr,"|_.__/ \\__,_|_|\\__,_|_| |_|\\___\\___|\n"); fprintf(stderr, " this is balance %d.%d\n", release, subrelease); fprintf(stderr, " Copyright (c) 2000-2009,2010\n"); fprintf(stderr, " by Inlab Software GmbH, Gruenwald, Germany.\n"); fprintf(stderr, " All rights reserved.\n"); fprintf(stderr, "\n"); fprintf(stderr, "usage:\n"); fprintf(stderr, " balance [-b addr] [-B addr] [-t sec] [-T sec] [-adfpHM] \\\n"); fprintf(stderr, " port [h1[:p1[:maxc1]] [!%%] [ ... hN[:pN[:maxcN]]]]\n"); fprintf(stderr, " balance [-b addr] -i [-d] port\n"); fprintf(stderr, " balance [-b addr] -c cmd [-d] port\n"); fprintf(stderr, "\n"); fprintf(stderr, " -a enable channel autodisable option\n"); fprintf(stderr, " -b host bind to specific address on listen\n"); fprintf(stderr, " -B host bind to specific address for outgoing connections\n"); fprintf(stderr, " -c cmd execute specified interactive command\n"); fprintf(stderr, " -d debugging on\n"); fprintf(stderr, " -f stay in foregound\n"); fprintf(stderr, " -i interactive control\n"); fprintf(stderr, " -H failover even if Hash Type is used\n"); fprintf(stderr, " -M use MMAP instead of SHM for IPC\n"); fprintf(stderr, " -p packetdump\n"); fprintf(stderr, " -t sec specify connect timeout in seconds (default=%d)\n", DEFAULTTIMEOUT); fprintf(stderr, " -T sec timeout (seconds) for select (0 => never) (default=%d)\n", DEFAULTSELTIMEOUT); fprintf(stderr, " ! separates channelgroups (declaring previous to be Round Robin)\n"); fprintf(stderr, " %% as !, but declaring previous group to be a Hash Type\n"); fprintf(stderr, "\n"); fprintf(stderr, "examples:\n"); fprintf(stderr, " balance smtp mailhost1:smtp mailhost2:25 mailhost3\n"); fprintf(stderr, " balance -i smtp\n"); fprintf(stderr, " balance -b 2001:DB8::1 80 10.1.1.1 10.1.1.2\n"); fprintf(stderr, " balance -b 2001:DB8::1 80\n"); fprintf(stderr, "\n"); exit(EX_USAGE); } // goto background: void background(void) { int childpid; if ((childpid = fork()) < 0) { fprintf(stderr, "cannot fork\n"); exit(EX_OSERR); } else { if (childpid > 0) { exit(EX_OK); /* parent */ } } #ifdef BalanceBSD setpgid(getpid(), 0); #else setpgrp(); #endif if(chdir("/") <0) fprintf(stderr, "cannot chdir\n"); close(0); close(1); close(2); } COMMON *makecommon(int argc, char **argv, int source_port) { int i; int group; int channel; COMMON *mycommon; int numchannels = argc - 1; // port number is first argument if (numchannels >= MAXCHANNELS) { fprintf(stderr, "MAXCHANNELS exceeded...\n"); exit(EX_USAGE); } if ((rendezvousfd = open(rendezvousfile, O_RDWR, 0)) < 0) { perror("open"); fprintf(stderr,"check rendezvousfile permissions [%s]\n",rendezvousfile); exit(EX_NOINPUT); } b_writelock(); if ((mycommon = (COMMON *) shm_malloc(rendezvousfile, sizeof(COMMON))) == NULL) { fprintf(stderr, "cannot alloc COMMON struct\n"); exit(EX_OSERR); } mycommon->pid = getpid(); mycommon->release = release; mycommon->subrelease = subrelease; for (group = 0; group < MAXGROUPS; group++) { grp_nchannels(mycommon, group) = 0; grp_current(mycommon, group) = 0; grp_type(mycommon, group) = GROUP_RR; // Default: RR } group = 0; channel = 0; for (i = 1; i < argc; i++) { if (!strcmp(argv[i], "!")) { // This is a normal "GROUP_RR"-Type of Group if(channel <= 0) { err_dump("no channels in group"); } grp_type(mycommon, group) = GROUP_RR; group++; channel = 0; if (group >= MAXGROUPS) { err_dump("too many groups"); } } else if (!strcmp(argv[i], "%")) { // This is a "GROUP_HASH" if(channel <= 0) { err_dump("no channels in group"); } grp_type(mycommon, group) = GROUP_HASH; group++; channel = 0; if (group >= MAXGROUPS) { err_dump("too many groups"); } } else { chn_status(mycommon, group, channel) = 1; chn_c(mycommon, group, channel) = 0; // connections... chn_tc(mycommon, group, channel) = 0; // total connections... chn_maxc(mycommon, group, channel) = 0; // maxconnections... setaddress(&chn_ipaddr(mycommon, group, channel), &chn_port(mycommon, group, channel), argv[i], source_port, &chn_maxc(mycommon, group, channel)); chn_bsent(mycommon, group, channel) = 0; chn_breceived(mycommon, group, channel) = 0; grp_nchannels(mycommon, group) += 1; channel++; if (channel >= MAXCHANNELS) { err_dump("too many channels in one group"); } } } if (debugflag) { fprintf(stderr, "the following channels are active:\n"); for (group = 0; group <= MAXGROUPS; group++) { for (i = 0; i < grp_nchannels(mycommon, group); i++) { fprintf(stderr, "%3d %2d %s:%d:%d\n", group, i, inet_ntoa(chn_ipaddr(mycommon, group, i)), chn_port(mycommon, group, i), chn_maxc(mycommon, group, i)); } } } b_unlock(); return (mycommon); } int mycmp(char *s1, char *s2) { int l; l = strlen(s1) < strlen(s2) ? strlen(s1) : strlen(s2); if (strlen(s1) > strlen(s2)) { return (!1); } else { return (!strncmp(s1, s2, l)); } } int shell(char *argument) { int i; int currentgroup = 0; char line[MAXINPUTLINE]; char *command; // DJJ, Standing Cloud, Inc. // In interactive mode, don't buffer stdout/stderr, so that // other programs can operate balance through I/O streams setvbuf(stdout, NULL, _IONBF, 0); setvbuf(stderr, NULL, _IONBF, 0); if (common->release == 0) { printf("no master process, exiting.\n"); exit(EX_UNAVAILABLE); } if (common->release != release || common->subrelease != subrelease) { printf("release mismatch, expecting %d.%d, got %d.%d, exiting.\n", release, subrelease, common->release, common->subrelease); exit(EX_DATAERR); } if (kill(common->pid, SIGUSR1) == -1) { printf("no master process with pid %d, exiting.\n", common->pid); exit(EX_UNAVAILABLE); } if (argument == NULL) { printf("\nbalance %d.%d interactive command shell\n", release, subrelease); printf("PID of master process is %d\n\n", common->pid); } for (;;) { if (argument == NULL) { printf("balance[%d] ", currentgroup); if (fgets(line, MAXINPUTLINE, stdin) == NULL) { printf("\n"); exit(EX_OK); } } else { strncpy(line, argument, MAXINPUTLINE); } if ((command = strtok(line, " \t\n")) != NULL) { if (mycmp(command, "quit")) { exit(EX_OK); } else if (mycmp(command, "show")) { b_readlock(); { int group; printf("%3s %4s %2s %3s %16s %5s %4s %11s %4s %11s %11s\n", "GRP", "Type", "#", "S", "ip-address", "port", "c", "totalc", "maxc", "sent", "rcvd"); for (group = 0; group <= MAXGROUPS; group++) { for (i = 0; i < grp_nchannels(common, group); i++) { printf("%3d %4s %2d %3s %16s %5d %4d %11u %4d %11llu %11llu\n", group, grp_type(common, group) == GROUP_RR ? "RR" : "Hash", i, chn_status(common, group, i) == 1 ? "ENA" : "dis", inet_ntoa(chn_ipaddr(common, group, i)), chn_port(common, group, i), chn_c(common, group, i), chn_tc(common, group, i), chn_maxc(common, group, i), chn_bsent(common, group, i), chn_breceived(common, group, i) ); } } } b_unlock(); } else if (mycmp(command, "help") || mycmp(command, "?")) { printf("available commands:\n"); printf(" create creates a channel in the current group\n"); printf(" assign reassigns a channel in the current group\n"); printf(" disable disables specified channel in current group\n"); printf(" enable enables channel in current group\n"); printf(" group changes current group to \n"); printf(" hash sets distribution scheme of current group to Hash\n"); printf(" help prints this message\n"); printf(" kill kills master process and quits interactive mode\n"); printf(" maxc specifies new maxc for channel of current group\n"); printf(" mrtg-bytes print bytes in/out in MRTG format\n"); printf(" mrtg-conns print total connections in MRTG format\n"); printf(" quit quit interactive mode\n"); printf(" reset reset all counters of channel in current group\n"); printf(" rr sets distribution scheme of current group to Round Robin\n"); printf(" show show all channels in all groups\n"); printf(" version show version id\n"); } else if (mycmp(command, "kill")) { kill(common->pid, SIGKILL); sleep(1); if (kill(common->pid, SIGUSR1) == -1) { printf("shutdown complete, exiting.\n"); common->release = 0; exit(EX_OK); } else { printf("shutdown failed.\n"); exit(EX_UNAVAILABLE); } } else if (mycmp(command, "disable")) { char *arg; int n; if ((arg = strtok(NULL, " \t\n")) != NULL) { n = atoi(arg); if (n < 0 || n >= grp_nchannels(common, currentgroup)) { printf("no such channel %d\n", n); } else { c_writelock(currentgroup, n); if (chn_status(common, currentgroup, n) == 0) { printf("channel %d already disabled\n", n); } else { chn_status(common, currentgroup, n) = 0; printf("channel %d disabled\n", n); } c_unlock(currentgroup, n); } } else { printf("syntax error\n"); } } else if (mycmp(command, "group")) { char *arg, n; if ((arg = strtok(NULL, " \t\n")) != NULL) { n = atoi(arg); if (n >= MAXGROUPS || n < 0) { printf("value out of range\n"); } else { currentgroup = n; } } else { printf("syntax error\n"); } } else if (mycmp(command, "reset")) { // reset channel counters char *arg; int n; if ((arg = strtok(NULL, " \t\n")) != NULL) { n = atoi(arg); if (n < 0 || n >= grp_nchannels(common, currentgroup)) { printf("no such channel %d\n", n); } else { c_writelock(currentgroup, n); chn_breceived(common, currentgroup, n) = 0; chn_bsent(common, currentgroup, n) = 0; chn_tc(common, currentgroup, n) = 0; c_unlock(currentgroup, n); printf("channel %d counters reset\n", n); } } else { printf("syntax error\n"); } } else if (mycmp(command, "enable")) { char *arg; int n; if ((arg = strtok(NULL, " \t\n")) != NULL) { n = atoi(arg); if (n < 0 || n >= grp_nchannels(common, currentgroup)) { printf("no such channel %d\n", n); } else { c_writelock(currentgroup, n); if (chn_status(common, currentgroup, n) == 1) { printf("channel %d already enabled\n", n); } else { chn_status(common, currentgroup, n) = 1; printf("channel %d enabled\n", n); } c_unlock(currentgroup, n); } } else { printf("syntax error\n"); } } else if (mycmp(command, "create")) { char *arg1, *arg2; b_writelock(); if (grp_nchannels(common, currentgroup) >= MAXCHANNELS) { printf("no channel slots available\n"); } else { if ((arg1 = strtok(NULL, " \t\n")) != NULL) { if ((arg2 = strtok(NULL, " \t\n")) != NULL) { chn_status(common, currentgroup, grp_nchannels(common, currentgroup)) = 0; if (setaddress_noexitonerror (&chn_ipaddr (common, currentgroup, grp_nchannels(common, currentgroup)), &chn_port(common, currentgroup, grp_nchannels (common, currentgroup)), arg1, getport(arg2))) { chn_bsent(common, currentgroup, grp_nchannels(common, currentgroup)) = 0; chn_breceived(common, currentgroup, grp_nchannels(common, currentgroup)) = 0; grp_nchannels(common, currentgroup)++; printf("channel created\n"); } else { printf("invalid address\n"); } } else { printf("syntax error\n"); } } else { printf("syntax error\n"); } } b_unlock(); } else if (mycmp(command, "assign")) { char *arg1, *arg2, *arg3; if ((arg1 = strtok(NULL, " \t\n")) != NULL) { int chn = atoi(arg1); if (chn < 0 || chn >= MAXCHANNELS || chn >= grp_nchannels(common, currentgroup)) { printf("unknown channel\n"); } else { c_writelock(currentgroup, chn); if (chn_status(common, currentgroup, chn) != 0) { printf("channel must be disabled to assign new address\n"); } else if ((arg2 = strtok(NULL, " \t\n")) != NULL) { if ((arg3 = strtok(NULL, " \t\n")) != NULL) { if (setaddress_noexitonerror (&chn_ipaddr(common, currentgroup, chn), &chn_port(common, currentgroup, chn), arg2, getport(arg3))) { printf("channel reassigned\n"); } else { printf("invalid address\n"); } } else { printf("syntax error\n"); } } else { printf("syntax error\n"); } c_unlock(currentgroup, chn); } } else { printf("syntax error\n"); } } else if (mycmp(command, "maxc")) { char *arg1, *arg2; b_writelock(); if ((arg1 = strtok(NULL, " \t\n")) != NULL) { if ((arg2 = strtok(NULL, " \t\n")) != NULL) { if (atoi(arg1) < 0 || atoi(arg1) >= MAXCHANNELS || atoi(arg1) + 1 > grp_nchannels(common, currentgroup)) { printf("unknown channel\n"); } else { chn_maxc(common, currentgroup, atoi(arg1)) = atoi(arg2); printf("maxc of channel %d changed to %d\n", atoi(arg1), atoi(arg2)); } } else { printf("syntax error\n"); } } else { printf("syntax error\n"); } b_unlock(); } else if (mycmp(command, "mrtg-bytes")) { char *arg1, *arg2; int mygroup, mychannel; b_writelock(); if ((arg1 = strtok(NULL, " \t\n")) != NULL) { if ((arg2 = strtok(NULL, " \t\n")) != NULL) { mygroup = atoi(arg1); mychannel = atoi(arg2); if (mygroup < 0 || mygroup > MAXGROUPS) { printf("unknown group\n"); } else { if(mychannel < 0 || mychannel > grp_nchannels(common, currentgroup)) { printf("unknown channel\n"); } else { // printf("%llu\n", chn_breceived(common,mygroup,mychannel)); printf("%llu\n", chn_bsent(common,mygroup,mychannel)); printf("UNKNOWN\n"); printf("group %d channel %d\n",mygroup, mychannel); } } } else { printf("syntax error\n"); } } else { printf("syntax error\n"); } b_unlock(); } else if (mycmp(command, "mrtg-conns")) { char *arg1, *arg2; int mygroup, mychannel; b_writelock(); if ((arg1 = strtok(NULL, " \t\n")) != NULL) { if ((arg2 = strtok(NULL, " \t\n")) != NULL) { mygroup = atoi(arg1); mychannel = atoi(arg2); if (mygroup < 0 || mygroup > MAXGROUPS) { printf("unknown group\n"); } else { if(mychannel < 0 || mychannel > grp_nchannels(common, currentgroup)) { printf("unknown channel\n"); } else { // printf("%u\n", chn_tc(common,mygroup,mychannel)); printf("UNKNOWN\n"); printf("UNKNOWN\n"); printf("group %d channel %d\n",mygroup, mychannel); } } } else { printf("syntax error\n"); } } else { printf("syntax error\n"); } b_unlock(); } else if (mycmp(command, "version")) { printf(" This is balance %d.%d\n", release, subrelease); printf(" MAXGROUPS=%d\n", MAXGROUPS); printf(" MAXCHANNELS=%d\n", MAXCHANNELS); } else if (mycmp(command, "hash")) { b_writelock(); grp_type(common, currentgroup) = GROUP_HASH; b_unlock(); printf("group %d set to hash\n", currentgroup); } else if (mycmp(command, "rr")) { b_writelock(); grp_type(common, currentgroup) = GROUP_RR; b_unlock(); printf("group %d set to round robin\n", currentgroup); } else { printf("syntax error\n"); } // printf("\n"); } if (argument != NULL) exit(EX_OK); } } char bindhost_address[FILENAMELEN]; int main(int argc, char *argv[]) { int startindex; int sockfd, newsockfd, childpid; unsigned int clilen; int c; int source_port; int fd; char *argument = NULL; struct stat buffer; struct sockaddr_storage cli_addr; struct sigaction usr1_action, chld_action; #ifdef BalanceBSD #else struct rlimit r; #endif connect_timeout = DEFAULTTIMEOUT; initialize_release_variables(); while ((c = getopt(argc, argv, "c:b:B:t:T:adfpiHM6")) != EOF) { switch (c) { case '6': bindipv6 = 1; break; case 'a': autodisable = 1; break; case 'b': bindhost = optarg; break; case 'B': outbindhost = optarg; break; case 'c': argument = optarg; interactive = 1; foreground = 1; packetdump = 0; break; case 't': connect_timeout = atoi(optarg); if (connect_timeout < 1) { usage(); } break; case 'T': sel_tmout.tv_sec = atoi(optarg); sel_tmout.tv_usec = 0; if (sel_tmout.tv_sec < 1) usage(); save_tmout = sel_tmout; break; case 'f': foreground = 1; break; case 'd': debugflag = 1; break; case 'p': packetdump = 1; break; case 'i': interactive = 1; foreground = 1; packetdump = 0; break; case 'H': hashfailover = 1; break; case 'M': #ifdef NO_MMAP fprintf(stderr, "Warning: Built without memory mapped file support, using IPC\n"); #else shmmapfile = 1; #endif break; case '?': default: usage(); } } if (debugflag) { printf("argv[0]=%s\n", argv[0]); printf("bindhost=%s\n", bindhost == NULL ? "NULL" : bindhost); } if (interactive) { foreground = 1; packetdump = 0; } argc -= optind; argv += optind; if (!interactive) { if (argc < 1) { usage(); } } else { if (argc != 1) { usage(); } } usr1_action.sa_handler = usr1_handler; usr1_action.sa_flags = SA_RESTART; sigemptyset(&usr1_action.sa_mask); sigaction(SIGUSR1, &usr1_action, NULL); chld_action.sa_handler = chld_handler; chld_action.sa_flags = SA_RESTART; sigemptyset(&chld_action.sa_mask); sigaction(SIGCHLD, &chld_action, NULL); // really dump core if something fails... #ifdef BalanceBSD #else getrlimit(RLIMIT_CORE, &r); r.rlim_cur = r.rlim_max; setrlimit(RLIMIT_CORE, &r); #endif // get the source port if ((source_port = getport(argv[0])) == 0) { fprintf(stderr, "invalid port [%s], exiting.\n", argv[0]); exit(EX_USAGE); } if (debugflag) { fprintf(stderr, "source port %d\n", source_port); } /* * Bind our local address so that the client can send to us. * Handling of -b option. */ if (bindhost != NULL) { snprintf(bindhost_address, FILENAMELEN, "%s", bindhost); } else { snprintf(bindhost_address, FILENAMELEN, "%s", "0.0.0.0"); } stat(SHMDIR, &buffer); if (!S_ISDIR(buffer.st_mode)) { mode_t old = umask(0); if (mkdir(SHMDIR, 01777) < 0) { if(errno != EEXIST) { fprintf(stderr, "ERROR: rendezvous directory not available and/or creatable\n"); fprintf(stderr, " please create %s with mode 01777 like this: \n", SHMDIR); fprintf(stderr, " # mkdir -m 01777 %s\n", SHMDIR); umask(old); exit(EX_UNAVAILABLE); } } umask(old); } sprintf(rendezvousfile, "%sbalance.%d.%s", SHMDIR, source_port, bindhost_address); if (stat(rendezvousfile, &buffer) == -1) { // File not existing yet ... if ((fd = open(rendezvousfile, O_CREAT | O_RDWR, 0666)) == -1) { fprintf(stderr, "cannot create rendezvous file %s\n", rendezvousfile); exit(EX_OSERR); } else { if (debugflag) fprintf(stderr, "file %s created\n", rendezvousfile); close(fd); } } else { if (debugflag) fprintf(stderr, "file %s already exists\n", rendezvousfile); } if (interactive) { // command mode ! if ((rendezvousfd = open(rendezvousfile, O_RDWR, 0)) < 0) { perror("open"); fprintf(stderr,"check rendezvousfile permissions [%s]\n",rendezvousfile); exit(EX_OSERR); } if ((common = (COMMON *) shm_malloc(rendezvousfile, sizeof(COMMON))) == NULL) { fprintf(stderr, "cannot alloc COMMON struct\n"); exit(EX_OSERR); } shell(argument); } openlog("Balance", LOG_ODELAY | LOG_PID | LOG_CONS, LOG_DAEMON); /* Open a TCP socket (an Internet stream socket). */ sockfd = create_serversocket(bindhost, argv[0]); (void) setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sockbufsize, sizeof(sockbufsize)); (void) setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &sockbufsize, sizeof(sockbufsize)); // init of common (*after* bind()) if (!foreground) { background(); } common = makecommon(argc, argv, source_port); for (;;) { int index; unsigned int uindex; int groupindex = 0; // always start at groupindex 0 clilen = sizeof(cli_addr); newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0) { if (debugflag) { fprintf(stderr, "accept error %d\n", errno); } continue; } if (debugflag) { char buf[1024]; inet_ntop(AF_INET6,&(((struct sockaddr_in6*) &cli_addr)->sin6_addr),buf,1024); fprintf(stderr, "connect from %s clilen=%d\n", buf, clilen); } /* * the balancing itself: * - groupindex = 0 * - decision wich channel to use for the first try * - client address available in cli_addr * */ b_writelock(); for (;;) { index = grp_current(common, groupindex); for (;;) { if (grp_type(common, groupindex) == GROUP_RR) { if (chn_status(common, groupindex, index) == 1 && (chn_maxc(common, groupindex, index) == 0 || (chn_c(common, groupindex, index) < chn_maxc(common, groupindex, index)))) { break; // channel found } else { index++; if (index >= grp_nchannels(common, groupindex)) { index = 0; } if (index == grp_current(common, groupindex)) { index = -1; // no channel available in this group break; } } } else if (grp_type(common, groupindex) == GROUP_HASH) { uindex = hash_fold((unsigned char*) &(((struct sockaddr_in6 *) &cli_addr)->sin6_addr), clilen); if(debugflag) { fprintf(stderr, "HASH-method: fold returns %u\n", uindex); } index = uindex % grp_nchannels(common, groupindex); if (debugflag) fprintf(stderr, "modulo %d gives %d\n", grp_nchannels(common, groupindex), index); if (chn_status(common, groupindex, index) == 1 && (chn_maxc(common, groupindex, index) == 0 || (chn_c(common, groupindex, index) < chn_maxc(common, groupindex, index))) ) { break; // channel found, channel valid for HASH } else { if (hashfailover == 1) { // if failover even if hash: try next channel in this group. if (debugflag) fprintf(stderr, "channel disabled - hashfailover.\n"); startindex = index; for (;;) { index++; if (index >= grp_nchannels(common, groupindex)) { index = 0; } if (index == startindex) { if (debugflag) fprintf(stderr, "no valid channel in group %d.\n", groupindex); index = -1; break; } if (chn_status(common, groupindex, index) == 1 && (chn_maxc(common, groupindex, index) == 0 || (chn_c(common, groupindex, index) < chn_maxc(common, groupindex, index))) ) { if (debugflag) fprintf(stderr, "channel choosen: %d in group %d.\n", index, groupindex); break; // channel found } } } else { if (debugflag) fprintf(stderr, "no valid channel in group %d. Failover?\n", groupindex); index = -1; } break; } } else { err_dump("PANIC: invalid group type"); } } // Hier fallen wir "raus" mit dem index in der momentanen Gruppe, oder -1 // wenn nicht moeglich in dieser Gruppe grp_current(common, groupindex) = index; grp_current(common, groupindex)++; // current index dieser gruppe wieder null, wenn vorher ungueltig (-1) // Der index der gruppe wird neu berechnet und gespeichert, "index" ist immer noch // -1 oder der zu waehlende index... if (grp_current(common, groupindex) >= grp_nchannels(common, groupindex)) { grp_current(common, groupindex) = 0; } if (index >= 0) { chn_c(common, groupindex, index)++; // we promise a successful connection chn_tc(common, groupindex, index)++; // also incrementing the total count // c++ break; // index in this group found } else { groupindex++; // try next group ! if (groupindex >= MAXGROUPS) { break; // end of groups... } } } b_unlock(); if (index >= 0) { if ((childpid = fork()) < 0) { // the connection is rejected if fork() returns error, // but main process stays alive ! if (debugflag) { fprintf(stderr, "fork error\n"); } } else if (childpid == 0) { // child process close(sockfd); // close original socket // FIX: "#8 SIGPIPE causes unclosed channels" signal(SIGPIPE, SIG_IGN); // process the request: stream(newsockfd, groupindex, index, (char *) &cli_addr, clilen); exit(EX_OK); } } close(newsockfd); // parent process } } } else { printf("syntax error\n"); } } else { printf("syntax error\n"); } b_unlock(); } else if (myc./balance-3.57/balance.h000064400001440000001000000066361251763562500144210ustar00tother00001460000100/* * balance.h */ /* * $Id: balance.h,v 1.2 2011/02/10 13:52:47 t Exp $ */ #include #include #include #include #include #include #include #include #include #ifndef NO_MMAP #include #include #endif #ifdef __FreeBSD__ #define BalanceBSD 1 #endif #ifdef bsdi #define BalanceBSD 1 #endif #ifdef BSD #define BalanceBSD 1 #endif #ifdef MAC_OS_X_VERSION_10_4 #define BalanceBSD 1 #endif #ifdef BalanceBSD #include #else #include #endif #include #include #include #include #include #include #include #include #include #include #include /* for TCP_NODELAY definition */ /* solaris 9, solaris 10 do not have INADDR_NONE */ #ifndef INADDR_NONE #define INADDR_NONE ((unsigned long) -1) #endif #define MAXTXSIZE (32*1024) #define FILENAMELEN 1024 /* * this should be a directory that isn't cleaned up periodically, or at * reboot of the machine (/tmp is cleaned at reboot on many OS versions) */ #define SHMDIR "/var/run/balance/" #define SHMFILESUFFIX ".shm" #define MAXCHANNELS 64 /* max channels in group */ #define MAXGROUPS 32 /* max groups */ #define MAXINPUTLINE 128 /* max line in input mode */ #define DEFAULTTIMEOUT 5 /* timeout for unreachable hosts */ #define DEFAULTSELTIMEOUT 0 /* timeout for select */ typedef struct { int status; int port; struct in_addr ipaddr; int c; /* current # of connections */ int tc; /* total # of connections */ int maxc; /* max # of connections, 0 = no limit */ unsigned long long bsent; /* bytes sent */ unsigned long long breceived; /* bytes received */ } CHANNEL; #define GROUP_RR 0 /* Round Robin */ #define GROUP_HASH 1 /* Hash on Client Address */ typedef struct { int nchannels; /* number of channels in group */ int current; /* current channel in group */ int type; /* either GROUP_RR or GROUP_HASH */ CHANNEL channels[MAXCHANNELS]; } GROUP; typedef struct { int release; int subrelease; int pid; GROUP groups[MAXGROUPS]; } COMMON; /* * Macros to access various elements of struct GROUP and struct CHANNEL * within COMMON array * * a pointer to variable of type COMMON * g group index * i channel index */ #define cmn_group(a,g) ((a)->groups[(g)]) #define grp_nchannels(a,g) (cmn_group((a),(g)).nchannels) #define grp_current(a,g) (cmn_group((a),(g)).current) #define grp_type(a,g) (cmn_group((a),(g)).type) #define grp_channel(a,g,i) (cmn_group((a),(g)).channels[(i)]) #define chn_status(a,g,i) (grp_channel((a),(g),(i)).status) #define chn_port(a,g,i) (grp_channel((a),(g),(i)).port) #define chn_ipaddr(a,g,i) (grp_channel((a),(g),(i)).ipaddr) #define chn_c(a,g,i) (grp_channel((a),(g),(i)).c) #define chn_tc(a,g,i) (grp_channel((a),(g),(i)).tc) #define chn_maxc(a,g,i) (grp_channel((a),(g),(i)).maxc) #define chn_bsent(a,g,i) (grp_channel((a),(g),(i)).bsent) #define chn_breceived(a,g,i) (grp_channel((a),(g),(i)).breceived) /* * function prototypes */ unsigned int hash_fold(char *, int); ssize_t writen(int, unsigned char *, size_t); ./balance-3.57/butils.c000064400001440000001000000013331251763562500143160ustar00tother00001460000100/* * Copyright (c) 2000-2004,2005 by Inlab Software GmbH, Gruenwald, Germany. * All rights reserved. * */ /* * $Id: butils.c,v 1.1 2010/01/29 10:40:16 t Exp $ */ #include char* butils_rcsid="$Id: butils.c,v 1.1 2010/01/29 10:40:16 t Exp $"; unsigned int hash_fold(char* s, int len) { unsigned int rc = 0; int i; for (i=0; i 0) { nwritten = write(fd, ptr, nleft); if (nwritten <= 0) { return (nwritten); /* error */ } nleft -= nwritten; ptr += nwritten; } return (nbytes - nleft); } ./balance-3.57/COPYING000044400001440000001000000353671251763562500137170ustar00tother00001460000100 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. 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.) 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. 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. 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. es 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 charg./balance-3.57/Makefile000064400001440000001000000035701251763562500143150ustar00tother00001460000100# $Id: Makefile,v 1.14 2015/04/28 07:49:37 t Exp t $ #CFLAGS=-g -I. CFLAGS=-O2 -Wall -Wstrict-prototypes -Wuninitialized # uncomment for any OS other than Cygwin BALANCE=balance ROOT=root INSTALL=install BINDIR=/usr/sbin MANDIR=${BINDIR}/../man/man1 # uncomment for Solaris: # LIBRARIES=-lsocket -lnsl # INSTALL=/usr/ucb/install # BINDIR=/usr/local/libexec # uncomment for Cygwin: # LIBRARIES=-L/usr/local/lib -lcygipc # BALANCE=balance.exe # ROOT=Administrators CC=gcc RELEASE=3.57 all: balance balance: balance.o butils.o $(CC) $(CFLAGS) -I. -o balance balance.o butils.o $(LIBRARIES) balance.o: balance.c balance.h $(CC) $(CFLAGS) -I. -c balance.c butils.o: butils.c balance.h $(CC) $(CFLAGS) -I. -c butils.c balance.pdf: balance.ps ps2pdf balance.ps balance.pdf balance.ps: balance.1 troff -Tpost -man balance.1 | /usr/lib/lp/postscript/dpost > balance.ps # groff -f H -man balance.1 > balance.ps ci: ci -l *.c *.h Makefile balance.1 README balance.spec clean: rm -f $(BALANCE) *.o balance.ps balance.pdf install: $(INSTALL) -o $(ROOT) -g $(ROOT) -m 755 $(BALANCE) \ $(DESTDIR)$(BINDIR)/$(BALANCE) $(INSTALL) -o $(ROOT) -g $(ROOT) -m 755 balance.1 \ $(DESTDIR)$(MANDIR) mkdir -p $(DESTDIR)/var/run/balance chmod 1777 $(DESTDIR)/var/run/balance release: balance.pdf rm -rf ./releases/balance-$(RELEASE) mkdir ./releases/balance-$(RELEASE) cp balance.1 balance.pdf balance.c balance.h butils.c COPYING Makefile README ./releases/balance-$(RELEASE) cp balance.spec ./releases/balance-$(RELEASE)/balance.spec cd releases; tar -cvf balance-$(RELEASE).tar ./balance-$(RELEASE) cd releases; gzip balance-$(RELEASE).tar rpm: ever cp releases/balance-$(RELEASE).tar.gz /usr/src/redhat/SOURCES/ rpmbuild -ba balance.spec cp /usr/src/redhat/SRPMS/balance-$(RELEASE)-1.src.rpm ./releases cp /usr/src/redhat/RPMS/i386/balance-$(RELEASE)-1.i386.rpm ./releases ever: ./balance-3.57/README000064400001440000001000000012541251763562500135320ustar00tother00001460000100 Welcome to the source code distribution of balance ! Installation: ------------- Linux (i386/itanium), FreeBSD, BSD/OS: make make install Solaris: Uncomment the LIBRARY and INSTALL definitions in the Makefile. make make install If you have any problems just change the very simple Makefile to fit your needs. Shared memory should be enabled on your machine. For cygwin uncomment the cygwin definitions in the Makefile first. Information about new releases, mailing lists and other related issues can be found at the balance homepage http://balance.sourceforge.net . Reports of successful use of balance are appreciated. Have fun... Thomas Obermair ./balance-3.57/balance.spec000064400001440000001000000034561251763562500151210ustar00tother00001460000100Summary: TCP load-balancing proxy server Name: balance Version: 3.54 Release: 1 Group: Networking/Daemons Source: http://www.inlab.de/%{name}-%{version}.tar.gz Copyright: Proprietary BuildRoot: %{_tmppath}/%{name}-buildroot %define strip_binaries 1 %define gzip_man 1 %define __prefix /usr Prefix: %{__prefix} %description Balance is a simple but powerful generic tcp proxy with round robin load balancing and failover mechanisms. The program behaviour can be controlled at runtime using a simple command line syntax. %prep %setup %build make CFLAGS="$RPM_OPT_FLAGS" %install [ "${RPM_BUILD_ROOT}" != "/" ] && /bin/rm -rf ${RPM_BUILD_ROOT} mkdir -p $RPM_BUILD_ROOT/usr/sbin mkdir -p $RPM_BUILD_ROOT%{_mandir}/man1 mkdir -p $RPM_BUILD_ROOT/var/run/balance chmod 1777 $RPM_BUILD_ROOT/var/run/balance install -m 755 -s balance $RPM_BUILD_ROOT/usr/sbin/balance install -m 644 balance.1 $RPM_BUILD_ROOT%{_mandir}/man1/balance.1 %if %{strip_binaries} { cd $RPM_BUILD_ROOT strip .%{__prefix}/sbin/balance || /bin/true } %if %{gzip_man} { cd $RPM_BUILD_ROOT gzip .%{_mandir}/man1/balance.1 } %endif %clean [ "${RPM_BUILD_ROOT}" != "/" ] && /bin/rm -rf ${RPM_BUILD_ROOT} %files %defattr(-,root,root) %doc README COPYING %{__prefix}/sbin/balance %{_mandir}/man1/balance.1.gz %dir /var/run/balance %changelog * Fri Dec 03 2010 T.Obermair > 3.54 - update version * Tue Apr 08 2008 T.Obermair > 3.42 - update version * Sat Nov 24 2007 T.Obermair > 3.40 - update version * Mon Jan 15 2007 T.Obermair > 3.35 - update version * Sat Mar 18 2006 T.Obermair > 3.34 - update version * Wed Oct 19 2005 T.Obermair > 3.28 - update version * Fri Oct 31 2003 Bojan Smojver 3.11-1 - update version * Mon Sep 22 2003 Thomas Steudten 3.10-2 - rebuild - fix/expand specfile