Mercurial > masqmail
comparison 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 |
comparison
equal
deleted
inserted
replaced
186:3dff59a4e764 | 187:bd7c52a36b0c |
---|---|
1 /* MasqMail | 1 /* MasqMail |
2 Copyright (C) 1999-2001 Oliver Kurth | 2 Copyright (C) 1999-2001 Oliver Kurth |
3 Copyright (C) 2010 markus schnalke <meillo@marmaro.de> | |
3 | 4 |
4 This program is free software; you can redistribute it and/or modify | 5 This program is free software; you can redistribute it and/or modify |
5 it under the terms of the GNU General Public License as published by | 6 it under the terms of the GNU General Public License as published by |
6 the Free Software Foundation; either version 2 of the License, or | 7 the Free Software Foundation; either version 2 of the License, or |
7 (at your option) any later version. | 8 (at your option) any later version. |
20 #include "config.h" | 21 #include "config.h" |
21 #include "masqmail.h" | 22 #include "masqmail.h" |
22 #include "readsock.h" | 23 #include "readsock.h" |
23 | 24 |
24 | 25 |
26 | |
27 gboolean | |
28 init_sockaddr(struct sockaddr_in * name, interface * iface) | |
29 { | |
30 struct hostent *he; | |
31 struct in_addr ia; | |
32 | |
33 if (inet_aton(iface->address, &ia) != 0) { | |
34 /* IP address */ | |
35 memcpy(&(name->sin_addr), &ia, sizeof(name->sin_addr)); | |
36 } else { | |
37 if ((he = gethostbyname(iface->address)) == NULL) { | |
38 logwrite(LOG_ALERT, "local address '%s' unknown. (deleting)\n", iface->address); | |
39 return FALSE; | |
40 } | |
41 memcpy(&(name->sin_addr), he->h_addr, sizeof(name->sin_addr)); | |
42 } | |
43 name->sin_family = AF_INET; | |
44 name->sin_port = htons(iface->port); | |
45 | |
46 return TRUE; | |
47 } | |
48 | |
49 | |
50 int | |
51 make_server_socket(interface * iface) | |
52 { | |
53 int sock = -1; | |
54 struct sockaddr_in server; | |
55 | |
56 memset(&server, 0, sizeof(struct sockaddr_in)); | |
57 | |
58 /* Create the socket. */ | |
59 sock = socket(PF_INET, SOCK_STREAM, 0); | |
60 if (sock < 0) { | |
61 logwrite(LOG_ALERT, "socket: %s\n", strerror(errno)); | |
62 return -1; | |
63 } | |
64 | |
65 if (init_sockaddr(&server, iface)) { | |
66 /* bind the socket */ | |
67 if (bind(sock, (struct sockaddr *) &server, sizeof(server)) < 0) { | |
68 logwrite(LOG_ALERT, "bind: %s\n", strerror(errno)); | |
69 return -1; | |
70 } | |
71 } else { | |
72 close(sock); | |
73 return -1; | |
74 } | |
75 | |
76 return sock; | |
77 } | |
78 | |
79 | |
80 | |
81 | |
25 gchar* | 82 gchar* |
26 mserver_detect_online(interface * iface) | 83 mserver_detect_online(interface * iface) |
27 { | 84 { |
28 struct sockaddr_in saddr; | 85 struct sockaddr_in saddr; |
29 gchar *ret = NULL; | 86 gchar *ret = NULL; |
30 | 87 |
31 if (init_sockaddr(&saddr, iface)) { | 88 if (!init_sockaddr(&saddr, iface)) { |
32 int sock = socket(PF_INET, SOCK_STREAM, 0); | 89 return NULL; |
33 int dup_sock; | 90 } |
34 if (connect(sock, (struct sockaddr *) (&saddr), sizeof(saddr)) == 0) { | 91 |
35 FILE *in, *out; | 92 int sock = socket(PF_INET, SOCK_STREAM, 0); |
36 char buf[256]; | 93 int dup_sock; |
37 | 94 if (connect(sock, (struct sockaddr *) (&saddr), sizeof(saddr)) != 0) { |
38 dup_sock = dup(sock); | 95 return NULL; |
39 out = fdopen(sock, "w"); | 96 } |
40 in = fdopen(dup_sock, "r"); | 97 |
41 | 98 FILE *in, *out; |
42 if (read_sockline(in, buf, 256, 15, READSOCKL_CHUG)) { | 99 char buf[256]; |
43 if (strncmp(buf, "READY", 5) == 0) { | 100 |
44 fprintf(out, "STAT\n"); | 101 dup_sock = dup(sock); |
45 fflush(out); | 102 out = fdopen(sock, "w"); |
46 if (read_sockline(in, buf, 256, 15, READSOCKL_CHUG)) { | 103 in = fdopen(dup_sock, "r"); |
47 if (strncmp(buf, "DOWN", 4) == 0) { | 104 |
48 ret = NULL; | 105 if (!read_sockline(in, buf, 256, 15, READSOCKL_CHUG)) { |
49 } else if (strncmp(buf, "UP", 2) == 0) { | 106 return NULL; |
50 gchar *p = buf + 3; | 107 } |
51 while ((*p != ':') && *p) | 108 |
52 p++; | 109 /* this is the protocol (reverse engineered): |
53 if (*p) { | 110 S: READY |
54 *p = 0; | 111 C: STAT |
55 p++; | 112 S: DOWN |
56 if ((atoi(p) >= 0) && *p) | 113 C: QUIT |
57 ret = g_strdup(buf + 3); | 114 -> offline |
58 } else | 115 |
59 logwrite(LOG_ALERT, "unexpected response from mserver after STAT cmd: %s", buf); | 116 S: READY |
60 } else { | 117 C: STAT |
61 logwrite(LOG_ALERT, "unexpected response from mserver after STAT cmd: %s", buf); | 118 S: UP foo:-1 |
62 } | 119 C: QUIT |
120 -> offline | |
121 | |
122 S: READY | |
123 C: STAT | |
124 S: UP foo:1 | |
125 C: QUIT | |
126 -> online, `foo' gets printed | |
127 */ | |
128 | |
129 if (strncmp(buf, "READY", 5) == 0) { | |
130 fprintf(out, "STAT\n"); | |
131 fflush(out); | |
132 if (read_sockline(in, buf, 256, 15, READSOCKL_CHUG)) { | |
133 if (strncmp(buf, "DOWN", 4) == 0) { | |
134 ret = NULL; | |
135 } else if (strncmp(buf, "UP", 2) == 0) { | |
136 gchar *p = buf + 3; | |
137 while ((*p != ':') && *p) { | |
138 p++; | |
139 } | |
140 if (*p) { | |
141 *p = '\0'; | |
142 p++; | |
143 if ((atoi(p) >= 0) && *p) { | |
144 /* `UP foo:N', where `N' is a non-negative number */ | |
145 ret = g_strdup(buf + 3); | |
63 } | 146 } |
147 } else { | |
148 fprintf(stderr, "unexpected response from mserver after STAT cmd: %s", buf); | |
64 } | 149 } |
65 fprintf(out, "QUIT"); | 150 } else { |
66 fflush(out); | 151 fprintf(stderr, "unexpected response from mserver after STAT cmd: %s", buf); |
67 | |
68 close(sock); | |
69 close(dup_sock); | |
70 fclose(in); | |
71 fclose(out); | |
72 } | 152 } |
73 } | 153 } |
74 } | 154 } |
155 fprintf(out, "QUIT"); | |
156 fflush(out); | |
157 | |
158 close(sock); | |
159 close(dup_sock); | |
160 fclose(in); | |
161 fclose(out); | |
162 | |
75 return ret; | 163 return ret; |
76 } | 164 } |
77 | 165 |
78 | 166 |
79 void | 167 void |
80 logwrite(int pri, const char *fmt, ...) | 168 logwrite(int pri, const char *fmt, ...) |
81 { | 169 { |
82 va_list args; | 170 va_list args; |
83 va_start(args, fmt); | 171 va_start(args, fmt); |
84 | 172 |
85 vfprintf(stdout, fmt, args); | 173 vfprintf(stderr, fmt, args); |
86 | 174 |
87 va_end(args); | 175 va_end(args); |
88 } | 176 } |
89 | 177 |
90 void | |
91 debugf(const char *fmt, ...) | |
92 { | |
93 va_list args; | |
94 va_start(args, fmt); | |
95 | |
96 vfprintf(stdout, fmt, args); | |
97 | |
98 va_end(args); | |
99 } | |
100 | 178 |
101 int | 179 int |
102 main(int argc, char *argv[]) | 180 main(int argc, char *argv[]) |
103 { | 181 { |
104 if (argc == 3) { | 182 interface iface; |
105 interface iface; | 183 gchar *name; |
106 gchar *name; | 184 |
107 | 185 if (argc != 3) { |
108 iface.address = g_strdup(argv[1]); | 186 fprintf(stderr, "usage: %s HOST PORT\n", argv[0]); |
109 iface.port = atoi(argv[2]); | 187 return 1; |
110 | 188 } |
111 name = mserver_detect_online(&iface); | 189 |
112 | 190 iface.address = g_strdup(argv[1]); |
191 iface.port = atoi(argv[2]); | |
192 | |
193 name = mserver_detect_online(&iface); | |
194 | |
195 if (name) { | |
113 printf("%s\n", name); | 196 printf("%s\n", name); |
114 | 197 return 0; |
115 exit(EXIT_SUCCESS); | 198 } |
116 } else { | 199 return 1; |
117 fprintf(stderr, "usage %s <host> <port>\n", argv[0]); | 200 } |
118 exit(EXIT_FAILURE); | |
119 } | |
120 } |