Skip to content

Instantly share code, notes, and snippets.

@Dyrcona
Created May 4, 2021 11:50
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Dyrcona/b60f239f382ee74c063d9138a2d815b2 to your computer and use it in GitHub Desktop.
Save Dyrcona/b60f239f382ee74c063d9138a2d815b2 to your computer and use it in GitHub Desktop.
A C program to check if a 3M SIP2 Protocol server is alive by sending the SC Status message.
/*
* Copyright © 2021 Jason J.A. Stephenson <jason@sigio.com>
*
* 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, see
* <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
/*
* This program is meant to be used as a health check for 3M SIP2
* Protocol servers with ldirectord or haproxy. It is specifically
* written to be used with the F/OSS Evergreen ILS SIPServer program.
* It *may* work with other SIP server implementations, but none have
* been tested.
*
* It sends a 3M SIP2 Protocol SC Status message (99) to the SIP
* server without logging in. The SIP server, therefore, must allow
* the SC Status message before login. This is accomplished for the
* Evergreen ILS SIPServer by adding allow_sc_status_then_login="true"
* to the configuration for the RAW transport service in the
* oils_sip.xml configuration file.
*
* NOTE: This program does NOT send the sequence nor checksum fields,
* as checksums are redundant over TCP connections. If your SIP
* server requires checksums, then you will have to add the code to
* generate the sequence and checksum and add them to the message.
*
* The program returns 0, which both ldirectord and haproxy accept as
* OK, if it can connect to the SIP server, send the SC Status message
* and receives the ACS Status message (98) from the server
* indicating the on-line status of the SIP server is OK, i.e. the
* message begins 98Y. If the connection fails, the SIP server
* doesn't respond or responds with a different message, then the
* program returns 1, which both ldirectord and haproxy interpret as
* failure. The load balancer/proxy will then follow its
* configuration for what to do with a failed server.
*
* The two load balancers both pass 4 arguments to the program, but
* the program only uses the 3rd and 4th arguments which correspond to
* the SIP server's real IP address and real port, respectively.
* These are used to connect to the SIP server and send the SC Status
* message.
*
* To install the program, you would first compile it (see below),
* then copy it to an accessible location on your load balancer or
* proxy servers (/usr/local/bin is common or a chroot is setup for
* haproxy), and adjust your load balancer or proxy configuration as
* appropriate to use the program to check the status of your SIP
* servers (see your software's documentation).
*
* compile (on Debian or Ubuntu GNU/Linux):
* cc -O2 -o sip2status sip2status.c
*/
int main(int argc, char *argv[]) {
int rv = 1; // Assume failure.
/* ldirectord/haproxy give us four or five arguments. We only care about 3 and 4. */
char *remoteIP = argv[3];
char *remotePort = argv[4];
char *message = "9902552.00\r";
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in remoteAddr;
memset(&remoteAddr, 0, sizeof(struct sockaddr_in));
remoteAddr.sin_family = AF_INET;
remoteAddr.sin_port = htons((uint16_t) atoi(remotePort));
inet_pton(AF_INET, remoteIP, &remoteAddr.sin_addr);
if (connect(sockfd, (struct sockaddr *)&remoteAddr, sizeof(remoteAddr)) != -1) {
if (write(sockfd, (void *)message, strlen(message)) != -1) {
char response[512]; // Certainly big enough...
memset(response, 0, 512);
if (read(sockfd, (void *)response, 511) != -1) {
if (strncmp(response, "98Y", 3) == 0)
rv = 0; // Success!
}
}
close(sockfd);
}
return rv;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment