changeset 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 3dff59a4e764
children bfa7a8b566da
files src/Makefile.am src/Makefile.in src/mservdetect.c
diffstat 3 files changed, 143 insertions(+), 65 deletions(-) [+]
line wrap: on
line diff
--- a/src/Makefile.am	Wed Jul 14 23:26:20 2010 +0200
+++ b/src/Makefile.am	Thu Jul 15 00:14:26 2010 +0200
@@ -71,7 +71,6 @@
 	masqmail.h\
 	readsock.h\
 	mservdetect.c\
-	interface.c\
 	readsock.c\
 	peopen.c
 
--- a/src/Makefile.in	Wed Jul 14 23:26:20 2010 +0200
+++ b/src/Makefile.in	Thu Jul 15 00:14:26 2010 +0200
@@ -61,8 +61,8 @@
 	timeival.$(OBJEXT)
 masqmail_OBJECTS = $(am_masqmail_OBJECTS)
 masqmail_DEPENDENCIES =
-am_mservdetect_OBJECTS = mservdetect.$(OBJEXT) interface.$(OBJEXT) \
-	readsock.$(OBJEXT) peopen.$(OBJEXT)
+am_mservdetect_OBJECTS = mservdetect.$(OBJEXT) readsock.$(OBJEXT) \
+	peopen.$(OBJEXT)
 mservdetect_OBJECTS = $(am_mservdetect_OBJECTS)
 mservdetect_DEPENDENCIES =
 am_readtest_OBJECTS = readsock.$(OBJEXT) readtest.$(OBJEXT)
@@ -299,7 +299,6 @@
 	masqmail.h\
 	readsock.h\
 	mservdetect.c\
-	interface.c\
 	readsock.c\
 	peopen.c
 
--- a/src/mservdetect.c	Wed Jul 14 23:26:20 2010 +0200
+++ b/src/mservdetect.c	Thu Jul 15 00:14:26 2010 +0200
@@ -1,5 +1,6 @@
 /*  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
@@ -22,56 +23,143 @@
 #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)) {
-		int sock = socket(PF_INET, SOCK_STREAM, 0);
-		int dup_sock;
-		if (connect(sock, (struct sockaddr *) (&saddr), sizeof(saddr)) == 0) {
-			FILE *in, *out;
-			char buf[256];
+	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;
+	}
 
-			dup_sock = dup(sock);
-			out = fdopen(sock, "w");
-			in = fdopen(dup_sock, "r");
+	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;
+	}
 
-			if (read_sockline(in, buf, 256, 15, READSOCKL_CHUG)) {
-				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)
-									ret = g_strdup(buf + 3);
-							} else
-								logwrite(LOG_ALERT, "unexpected response from mserver after STAT cmd: %s", buf);
-						} else {
-							logwrite(LOG_ALERT, "unexpected response from mserver after STAT cmd: %s", buf);
-						}
+	/* 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);
 				}
-				fprintf(out, "QUIT");
-				fflush(out);
-
-				close(sock);
-				close(dup_sock);
-				fclose(in);
-				fclose(out);
+			} 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;
 }
 
@@ -82,39 +170,31 @@
 	va_list args;
 	va_start(args, fmt);
 
-	vfprintf(stdout, fmt, args);
-
-	va_end(args);
-}
-
-void
-debugf(const char *fmt, ...)
-{
-	va_list args;
-	va_start(args, fmt);
-
-	vfprintf(stdout, fmt, args);
+	vfprintf(stderr, fmt, args);
 
 	va_end(args);
 }
 
+
 int
 main(int argc, char *argv[])
 {
-	if (argc == 3) {
-		interface iface;
-		gchar *name;
+	interface iface;
+	gchar *name;
 
-		iface.address = g_strdup(argv[1]);
-		iface.port = atoi(argv[2]);
-
-		name = mserver_detect_online(&iface);
+	if (argc != 3) {
+		fprintf(stderr, "usage: %s HOST PORT\n", argv[0]);
+		return 1;
+	}
 
-		printf("%s\n", name);
+	iface.address = g_strdup(argv[1]);
+	iface.port = atoi(argv[2]);
+
+	name = mserver_detect_online(&iface);
 
-		exit(EXIT_SUCCESS);
-	} else {
-		fprintf(stderr, "usage %s <host> <port>\n", argv[0]);
-		exit(EXIT_FAILURE);
+	if (name) {
+		printf("%s\n", name);
+		return 0;
 	}
+	return 1;
 }