masqmail

diff 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 diff
     1.1 --- a/src/mservdetect.c	Wed Jul 14 23:26:20 2010 +0200
     1.2 +++ b/src/mservdetect.c	Thu Jul 15 00:14:26 2010 +0200
     1.3 @@ -1,5 +1,6 @@
     1.4  /*  MasqMail
     1.5      Copyright (C) 1999-2001 Oliver Kurth
     1.6 +    Copyright (C) 2010 markus schnalke <meillo@marmaro.de>
     1.7  
     1.8      This program is free software; you can redistribute it and/or modify
     1.9      it under the terms of the GNU General Public License as published by
    1.10 @@ -22,56 +23,143 @@
    1.11  #include "readsock.h"
    1.12  
    1.13  
    1.14 +
    1.15 +gboolean
    1.16 +init_sockaddr(struct sockaddr_in * name, interface * iface)
    1.17 +{
    1.18 +	struct hostent *he;
    1.19 +	struct in_addr ia;
    1.20 +
    1.21 +	if (inet_aton(iface->address, &ia) != 0) {
    1.22 +		/* IP address */
    1.23 +		memcpy(&(name->sin_addr), &ia, sizeof(name->sin_addr));
    1.24 +	} else {
    1.25 +		if ((he = gethostbyname(iface->address)) == NULL) {
    1.26 +			logwrite(LOG_ALERT, "local address '%s' unknown. (deleting)\n", iface->address);
    1.27 +			return FALSE;
    1.28 +		}
    1.29 +		memcpy(&(name->sin_addr), he->h_addr, sizeof(name->sin_addr));
    1.30 +	}
    1.31 +	name->sin_family = AF_INET;
    1.32 +	name->sin_port = htons(iface->port);
    1.33 +
    1.34 +	return TRUE;
    1.35 +}
    1.36 +
    1.37 +
    1.38 +int
    1.39 +make_server_socket(interface * iface)
    1.40 +{
    1.41 +	int sock = -1;
    1.42 +	struct sockaddr_in server;
    1.43 +
    1.44 +	memset(&server, 0, sizeof(struct sockaddr_in));
    1.45 +
    1.46 +	/* Create the socket. */
    1.47 +	sock = socket(PF_INET, SOCK_STREAM, 0);
    1.48 +	if (sock < 0) {
    1.49 +		logwrite(LOG_ALERT, "socket: %s\n", strerror(errno));
    1.50 +		return -1;
    1.51 +	}
    1.52 +
    1.53 +	if (init_sockaddr(&server, iface)) {
    1.54 +		/* bind the socket */
    1.55 +		if (bind(sock, (struct sockaddr *) &server, sizeof(server)) < 0) {
    1.56 +			logwrite(LOG_ALERT, "bind: %s\n", strerror(errno));
    1.57 +			return -1;
    1.58 +		}
    1.59 +	} else {
    1.60 +		close(sock);
    1.61 +		return -1;
    1.62 +	}
    1.63 +
    1.64 +	return sock;
    1.65 +}
    1.66 +
    1.67 +
    1.68 +
    1.69 +
    1.70  gchar*
    1.71  mserver_detect_online(interface * iface)
    1.72  {
    1.73  	struct sockaddr_in saddr;
    1.74  	gchar *ret = NULL;
    1.75  
    1.76 -	if (init_sockaddr(&saddr, iface)) {
    1.77 -		int sock = socket(PF_INET, SOCK_STREAM, 0);
    1.78 -		int dup_sock;
    1.79 -		if (connect(sock, (struct sockaddr *) (&saddr), sizeof(saddr)) == 0) {
    1.80 -			FILE *in, *out;
    1.81 -			char buf[256];
    1.82 +	if (!init_sockaddr(&saddr, iface)) {
    1.83 +		return NULL;
    1.84 +	}
    1.85  
    1.86 -			dup_sock = dup(sock);
    1.87 -			out = fdopen(sock, "w");
    1.88 -			in = fdopen(dup_sock, "r");
    1.89 +	int sock = socket(PF_INET, SOCK_STREAM, 0);
    1.90 +	int dup_sock;
    1.91 +	if (connect(sock, (struct sockaddr *) (&saddr), sizeof(saddr)) != 0) {
    1.92 +		return NULL;
    1.93 +	}
    1.94  
    1.95 -			if (read_sockline(in, buf, 256, 15, READSOCKL_CHUG)) {
    1.96 -				if (strncmp(buf, "READY", 5) == 0) {
    1.97 -					fprintf(out, "STAT\n");
    1.98 -					fflush(out);
    1.99 -					if (read_sockline(in, buf, 256, 15, READSOCKL_CHUG)) {
   1.100 -						if (strncmp(buf, "DOWN", 4) == 0) {
   1.101 -							ret = NULL;
   1.102 -						} else if (strncmp(buf, "UP", 2) == 0) {
   1.103 -							gchar *p = buf + 3;
   1.104 -							while ((*p != ':') && *p)
   1.105 -								p++;
   1.106 -							if (*p) {
   1.107 -								*p = 0;
   1.108 -								p++;
   1.109 -								if ((atoi(p) >= 0) && *p)
   1.110 -									ret = g_strdup(buf + 3);
   1.111 -							} else
   1.112 -								logwrite(LOG_ALERT, "unexpected response from mserver after STAT cmd: %s", buf);
   1.113 -						} else {
   1.114 -							logwrite(LOG_ALERT, "unexpected response from mserver after STAT cmd: %s", buf);
   1.115 -						}
   1.116 +	FILE *in, *out;
   1.117 +	char buf[256];
   1.118 +
   1.119 +	dup_sock = dup(sock);
   1.120 +	out = fdopen(sock, "w");
   1.121 +	in = fdopen(dup_sock, "r");
   1.122 +
   1.123 +	if (!read_sockline(in, buf, 256, 15, READSOCKL_CHUG)) {
   1.124 +		return NULL;
   1.125 +	}
   1.126 +
   1.127 +	/* this is the protocol (reverse engineered):
   1.128 +	   S: READY
   1.129 +	   C: STAT
   1.130 +	   S: DOWN
   1.131 +	   C: QUIT
   1.132 +	   -> offline
   1.133 +	   
   1.134 +	   S: READY
   1.135 +	   C: STAT
   1.136 +	   S: UP foo:-1
   1.137 +	   C: QUIT
   1.138 +	   -> offline
   1.139 +	   
   1.140 +	   S: READY
   1.141 +	   C: STAT
   1.142 +	   S: UP foo:1
   1.143 +	   C: QUIT
   1.144 +	   -> online, `foo' gets printed
   1.145 +	*/
   1.146 +
   1.147 +	if (strncmp(buf, "READY", 5) == 0) {
   1.148 +		fprintf(out, "STAT\n");
   1.149 +		fflush(out);
   1.150 +		if (read_sockline(in, buf, 256, 15, READSOCKL_CHUG)) {
   1.151 +			if (strncmp(buf, "DOWN", 4) == 0) {
   1.152 +				ret = NULL;
   1.153 +			} else if (strncmp(buf, "UP", 2) == 0) {
   1.154 +				gchar *p = buf + 3;
   1.155 +				while ((*p != ':') && *p) {
   1.156 +					p++;
   1.157 +				}
   1.158 +				if (*p) {
   1.159 +					*p = '\0';
   1.160 +					p++;
   1.161 +					if ((atoi(p) >= 0) && *p) {
   1.162 +						/* `UP foo:N', where `N' is a non-negative number */
   1.163 +						ret = g_strdup(buf + 3);
   1.164  					}
   1.165 +				} else {
   1.166 +					fprintf(stderr, "unexpected response from mserver after STAT cmd: %s", buf);
   1.167  				}
   1.168 -				fprintf(out, "QUIT");
   1.169 -				fflush(out);
   1.170 -
   1.171 -				close(sock);
   1.172 -				close(dup_sock);
   1.173 -				fclose(in);
   1.174 -				fclose(out);
   1.175 +			} else {
   1.176 +				fprintf(stderr, "unexpected response from mserver after STAT cmd: %s", buf);
   1.177  			}
   1.178  		}
   1.179  	}
   1.180 +	fprintf(out, "QUIT");
   1.181 +	fflush(out);
   1.182 +
   1.183 +	close(sock);
   1.184 +	close(dup_sock);
   1.185 +	fclose(in);
   1.186 +	fclose(out);
   1.187 +
   1.188  	return ret;
   1.189  }
   1.190  
   1.191 @@ -82,39 +170,31 @@
   1.192  	va_list args;
   1.193  	va_start(args, fmt);
   1.194  
   1.195 -	vfprintf(stdout, fmt, args);
   1.196 +	vfprintf(stderr, fmt, args);
   1.197  
   1.198  	va_end(args);
   1.199  }
   1.200  
   1.201 -void
   1.202 -debugf(const char *fmt, ...)
   1.203 -{
   1.204 -	va_list args;
   1.205 -	va_start(args, fmt);
   1.206 -
   1.207 -	vfprintf(stdout, fmt, args);
   1.208 -
   1.209 -	va_end(args);
   1.210 -}
   1.211  
   1.212  int
   1.213  main(int argc, char *argv[])
   1.214  {
   1.215 -	if (argc == 3) {
   1.216 -		interface iface;
   1.217 -		gchar *name;
   1.218 +	interface iface;
   1.219 +	gchar *name;
   1.220  
   1.221 -		iface.address = g_strdup(argv[1]);
   1.222 -		iface.port = atoi(argv[2]);
   1.223 +	if (argc != 3) {
   1.224 +		fprintf(stderr, "usage: %s HOST PORT\n", argv[0]);
   1.225 +		return 1;
   1.226 +	}
   1.227  
   1.228 -		name = mserver_detect_online(&iface);
   1.229 +	iface.address = g_strdup(argv[1]);
   1.230 +	iface.port = atoi(argv[2]);
   1.231  
   1.232 +	name = mserver_detect_online(&iface);
   1.233 +
   1.234 +	if (name) {
   1.235  		printf("%s\n", name);
   1.236 -
   1.237 -		exit(EXIT_SUCCESS);
   1.238 -	} else {
   1.239 -		fprintf(stderr, "usage %s <host> <port>\n", argv[0]);
   1.240 -		exit(EXIT_FAILURE);
   1.241 +		return 0;
   1.242  	}
   1.243 +	return 1;
   1.244  }