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 }