Mercurial > masqmail
view src/mservdetect.c @ 187:bd7c52a36b0c
improved mservdetect in various ways
errors are handled better (no segfaults anymore)
copied the relevant part of interface.c into mservdetect.c
described how I think the mserver protocol works
author | meillo@marmaro.de |
---|---|
date | Thu, 15 Jul 2010 00:14:26 +0200 |
parents | 5b621742b2e7 |
children | bfa7a8b566da |
line wrap: on
line source
/* MasqMail Copyright (C) 1999-2001 Oliver Kurth Copyright (C) 2010 markus schnalke <meillo@marmaro.de> 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include "masqmail.h" #include "readsock.h" gboolean init_sockaddr(struct sockaddr_in * name, interface * iface) { struct hostent *he; struct in_addr ia; if (inet_aton(iface->address, &ia) != 0) { /* IP address */ memcpy(&(name->sin_addr), &ia, sizeof(name->sin_addr)); } else { if ((he = gethostbyname(iface->address)) == NULL) { logwrite(LOG_ALERT, "local address '%s' unknown. (deleting)\n", iface->address); return FALSE; } memcpy(&(name->sin_addr), he->h_addr, sizeof(name->sin_addr)); } name->sin_family = AF_INET; name->sin_port = htons(iface->port); return TRUE; } int make_server_socket(interface * iface) { int sock = -1; struct sockaddr_in server; memset(&server, 0, sizeof(struct sockaddr_in)); /* Create the socket. */ sock = socket(PF_INET, SOCK_STREAM, 0); if (sock < 0) { logwrite(LOG_ALERT, "socket: %s\n", strerror(errno)); return -1; } if (init_sockaddr(&server, iface)) { /* bind the socket */ if (bind(sock, (struct sockaddr *) &server, sizeof(server)) < 0) { logwrite(LOG_ALERT, "bind: %s\n", strerror(errno)); return -1; } } else { close(sock); return -1; } return sock; } gchar* mserver_detect_online(interface * iface) { struct sockaddr_in saddr; gchar *ret = NULL; if (!init_sockaddr(&saddr, iface)) { return NULL; } int sock = socket(PF_INET, SOCK_STREAM, 0); int dup_sock; if (connect(sock, (struct sockaddr *) (&saddr), sizeof(saddr)) != 0) { return NULL; } FILE *in, *out; char buf[256]; dup_sock = dup(sock); out = fdopen(sock, "w"); in = fdopen(dup_sock, "r"); if (!read_sockline(in, buf, 256, 15, READSOCKL_CHUG)) { return NULL; } /* this is the protocol (reverse engineered): S: READY C: STAT S: DOWN C: QUIT -> offline S: READY C: STAT S: UP foo:-1 C: QUIT -> offline S: READY C: STAT S: UP foo:1 C: QUIT -> online, `foo' gets printed */ if (strncmp(buf, "READY", 5) == 0) { fprintf(out, "STAT\n"); fflush(out); if (read_sockline(in, buf, 256, 15, READSOCKL_CHUG)) { if (strncmp(buf, "DOWN", 4) == 0) { ret = NULL; } else if (strncmp(buf, "UP", 2) == 0) { gchar *p = buf + 3; while ((*p != ':') && *p) { p++; } if (*p) { *p = '\0'; p++; if ((atoi(p) >= 0) && *p) { /* `UP foo:N', where `N' is a non-negative number */ ret = g_strdup(buf + 3); } } else { fprintf(stderr, "unexpected response from mserver after STAT cmd: %s", buf); } } else { fprintf(stderr, "unexpected response from mserver after STAT cmd: %s", buf); } } } fprintf(out, "QUIT"); fflush(out); close(sock); close(dup_sock); fclose(in); fclose(out); return ret; } void logwrite(int pri, const char *fmt, ...) { va_list args; va_start(args, fmt); vfprintf(stderr, fmt, args); va_end(args); } int main(int argc, char *argv[]) { interface iface; gchar *name; if (argc != 3) { fprintf(stderr, "usage: %s HOST PORT\n", argv[0]); return 1; } iface.address = g_strdup(argv[1]); iface.port = atoi(argv[2]); name = mserver_detect_online(&iface); if (name) { printf("%s\n", name); return 0; } return 1; }