Mercurial > pidgin.yaz
comparison src/proxy.c @ 1840:00aef397a1fe
[gaim-migrate @ 1850]
reworked some of the proxy stuff so that it's non-blocking now. next thing to do is to get IRC, MSN, Napster, and Jabber to use the new proxy_connect code. After that, Oscar and Yahoo (maybe Zephyr too? not likely)
committer: Tailor Script <tailor@pidgin.im>
| author | Eric Warmenhoven <eric@warmenhoven.org> |
|---|---|
| date | Sat, 12 May 2001 01:38:04 +0000 |
| parents | b4d454e5ee31 |
| children | 4dbd8533d209 |
comparison
equal
deleted
inserted
replaced
| 1839:109cacf1ff97 | 1840:00aef397a1fe |
|---|---|
| 32 #include <sys/types.h> | 32 #include <sys/types.h> |
| 33 #include <sys/socket.h> | 33 #include <sys/socket.h> |
| 34 #include <netdb.h> | 34 #include <netdb.h> |
| 35 #include <netinet/in.h> | 35 #include <netinet/in.h> |
| 36 #include <unistd.h> | 36 #include <unistd.h> |
| 37 #include <fcntl.h> | |
| 38 #include <errno.h> | |
| 37 #include <gtk/gtk.h> | 39 #include <gtk/gtk.h> |
| 38 #include "gaim.h" | 40 #include "gaim.h" |
| 39 #include "proxy.h" | 41 #include "proxy.h" |
| 40 | 42 |
| 41 static int proxy_connect_none(char *host, unsigned short port) | 43 struct PHB { |
| 44 GdkInputFunction func; | |
| 45 gpointer data; | |
| 46 char *host; | |
| 47 int port; | |
| 48 gint inpa; | |
| 49 }; | |
| 50 | |
| 51 static void no_one_calls(gpointer data, gint source, GdkInputCondition cond) | |
| 52 { | |
| 53 struct PHB *phb = data; | |
| 54 int len, error = ETIMEDOUT; | |
| 55 debug_printf("Connected\n"); | |
| 56 len = sizeof(error); | |
| 57 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | |
| 58 close(source); | |
| 59 gdk_input_remove(phb->inpa); | |
| 60 phb->func(phb->data, -1, GDK_INPUT_READ); | |
| 61 g_free(phb); | |
| 62 return; | |
| 63 } | |
| 64 fcntl(source, F_SETFL, 0); | |
| 65 gdk_input_remove(phb->inpa); | |
| 66 phb->func(phb->data, source, GDK_INPUT_READ); | |
| 67 g_free(phb); | |
| 68 } | |
| 69 | |
| 70 static int proxy_connect_none(char *host, unsigned short port, struct PHB *phb) | |
| 42 { | 71 { |
| 43 struct sockaddr_in sin; | 72 struct sockaddr_in sin; |
| 44 struct hostent *hp; | 73 struct hostent *hp; |
| 45 int fd = -1; | 74 int fd = -1; |
| 46 | 75 |
| 47 debug_printf("connecting to %s:%d with no proxy\n", host, port); | 76 debug_printf("connecting to %s:%d with no proxy\n", host, port); |
| 48 | 77 |
| 49 if (!(hp = gethostbyname(host))) | 78 if (!(hp = gethostbyname(host))) { |
| 50 return -1; | 79 g_free(phb); |
| 80 return -1; | |
| 81 } | |
| 51 | 82 |
| 52 memset(&sin, 0, sizeof(struct sockaddr_in)); | 83 memset(&sin, 0, sizeof(struct sockaddr_in)); |
| 53 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); | 84 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); |
| 54 sin.sin_family = hp->h_addrtype; | 85 sin.sin_family = hp->h_addrtype; |
| 55 sin.sin_port = htons(port); | 86 sin.sin_port = htons(port); |
| 56 | 87 |
| 57 if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) | 88 if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) { |
| 58 return -1; | 89 g_free(phb); |
| 59 | 90 return -1; |
| 91 } | |
| 92 | |
| 93 fcntl(fd, F_SETFL, O_NONBLOCK); | |
| 60 if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { | 94 if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { |
| 61 close(fd); | 95 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 62 return -1; | 96 debug_printf("Connect would have blocked\n"); |
| 97 phb->inpa = gdk_input_add(fd, GDK_INPUT_WRITE, no_one_calls, phb); | |
| 98 } else { | |
| 99 close(fd); | |
| 100 g_free(phb); | |
| 101 return -1; | |
| 102 } | |
| 103 } else { | |
| 104 int len, error = ETIMEDOUT; | |
| 105 debug_printf("Connect didn't block\n"); | |
| 106 len = sizeof(error); | |
| 107 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | |
| 108 close(fd); | |
| 109 g_free(phb); | |
| 110 return -1; | |
| 111 } | |
| 112 fcntl(fd, F_SETFL, 0); | |
| 113 phb->func(phb->data, fd, GDK_INPUT_READ); | |
| 114 g_free(phb); | |
| 63 } | 115 } |
| 64 | 116 |
| 65 return fd; | 117 return fd; |
| 66 } | 118 } |
| 67 | 119 |
| 68 #define HTTP_GOODSTRING "HTTP/1.0 200 Connection established" | 120 #define HTTP_GOODSTRING "HTTP/1.0 200 Connection established" |
| 69 #define HTTP_GOODSTRING2 "HTTP/1.1 200 Connection established" | 121 #define HTTP_GOODSTRING2 "HTTP/1.1 200 Connection established" |
| 70 | 122 |
| 71 static int proxy_connect_http(char *host, unsigned short port, char *proxyhost, unsigned short proxyport) | 123 static void http_canread(gpointer data, gint source, GdkInputCondition cond) |
| 124 { | |
| 125 int nlc = 0; | |
| 126 int pos = 0; | |
| 127 struct PHB *phb = data; | |
| 128 char inputline[8192]; | |
| 129 | |
| 130 gdk_input_remove(phb->inpa); | |
| 131 | |
| 132 while ((nlc != 2) && (read(source, &inputline[pos++], 1) == 1)) { | |
| 133 if (inputline[pos-1] == '\n') | |
| 134 nlc++; | |
| 135 else if (inputline[pos-1] != '\r') | |
| 136 nlc = 0; | |
| 137 } | |
| 138 inputline[pos] = '\0'; | |
| 139 | |
| 140 debug_printf("Proxy says: %s\n", inputline); | |
| 141 | |
| 142 if ((memcmp(HTTP_GOODSTRING , inputline, strlen(HTTP_GOODSTRING )) == 0) || | |
| 143 (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { | |
| 144 phb->func(phb->data, source, GDK_INPUT_READ); | |
| 145 g_free(phb->host); | |
| 146 g_free(phb); | |
| 147 return; | |
| 148 } | |
| 149 | |
| 150 close(source); | |
| 151 phb->func(phb->data, -1, GDK_INPUT_READ); | |
| 152 g_free(phb->host); | |
| 153 g_free(phb); | |
| 154 return; | |
| 155 } | |
| 156 | |
| 157 static void http_canwrite(gpointer data, gint source, GdkInputCondition cond) | |
| 158 { | |
| 159 char cmd[384]; | |
| 160 struct PHB *phb = data; | |
| 161 int len, error = ETIMEDOUT; | |
| 162 debug_printf("Connected\n"); | |
| 163 if (phb->inpa > 0) | |
| 164 gdk_input_remove(phb->inpa); | |
| 165 len = sizeof(error); | |
| 166 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | |
| 167 close(source); | |
| 168 phb->func(phb->data, -1, GDK_INPUT_READ); | |
| 169 g_free(phb->host); | |
| 170 g_free(phb); | |
| 171 return; | |
| 172 } | |
| 173 fcntl(source, F_SETFL, 0); | |
| 174 | |
| 175 snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\r\n\r\n", phb->host, phb->port); | |
| 176 if (send(source, cmd, strlen(cmd), 0) < 0) { | |
| 177 close(source); | |
| 178 phb->func(phb->data, -1, GDK_INPUT_READ); | |
| 179 g_free(phb->host); | |
| 180 g_free(phb); | |
| 181 return; | |
| 182 } | |
| 183 | |
| 184 phb->inpa = gdk_input_add(source, GDK_INPUT_READ, http_canread, phb); | |
| 185 } | |
| 186 | |
| 187 static int proxy_connect_http(char *host, unsigned short port, | |
| 188 char *proxyhost, unsigned short proxyport, | |
| 189 struct PHB *phb) | |
| 72 { | 190 { |
| 73 struct hostent *hp; | 191 struct hostent *hp; |
| 74 struct sockaddr_in sin; | 192 struct sockaddr_in sin; |
| 75 int fd = -1; | 193 int fd = -1; |
| 76 char cmd[384]; | |
| 77 char inputline[8192]; | |
| 78 int nlc = 0; | |
| 79 int pos = 0; | |
| 80 | 194 |
| 81 debug_printf("connecting to %s:%d via %s:%d using HTTP\n", host, port, proxyhost, proxyport); | 195 debug_printf("connecting to %s:%d via %s:%d using HTTP\n", host, port, proxyhost, proxyport); |
| 82 | 196 |
| 83 if (!(hp = gethostbyname(proxyhost))) | 197 if (!(hp = gethostbyname(proxyhost))) { |
| 84 return -1; | 198 g_free(phb); |
| 199 return -1; | |
| 200 } | |
| 85 | 201 |
| 86 memset(&sin, 0, sizeof(struct sockaddr_in)); | 202 memset(&sin, 0, sizeof(struct sockaddr_in)); |
| 87 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); | 203 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); |
| 88 sin.sin_family = hp->h_addrtype; | 204 sin.sin_family = hp->h_addrtype; |
| 89 sin.sin_port = htons(proxyport); | 205 sin.sin_port = htons(proxyport); |
| 90 | 206 |
| 91 if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) | 207 if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) { |
| 92 return -1; | 208 g_free(phb); |
| 93 | 209 return -1; |
| 210 } | |
| 211 | |
| 212 phb->host = g_strdup(host); | |
| 213 phb->port = port; | |
| 214 | |
| 215 fcntl(fd, F_SETFL, O_NONBLOCK); | |
| 94 if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { | 216 if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { |
| 95 close(fd); | 217 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 96 return -1; | 218 debug_printf("Connect would have blocked\n"); |
| 97 } | 219 phb->inpa = gdk_input_add(fd, GDK_INPUT_WRITE, http_canwrite, phb); |
| 98 | 220 } else { |
| 99 snprintf(cmd, sizeof(cmd), "CONNECT %s:%d HTTP/1.1\r\n\r\n", host, port); | 221 close(fd); |
| 100 | 222 g_free(phb->host); |
| 101 if (send(fd, cmd, strlen(cmd), 0) < 0) { | 223 g_free(phb); |
| 102 close(fd); | 224 return -1; |
| 103 return -1; | 225 } |
| 104 } | 226 } else { |
| 105 while ((nlc != 2) && (read(fd, &inputline[pos++], 1) == 1)) { | 227 int len, error = ETIMEDOUT; |
| 106 if (inputline[pos-1] == '\n') | 228 debug_printf("Connect didn't block\n"); |
| 107 nlc++; | 229 len = sizeof(error); |
| 108 else if (inputline[pos-1] != '\r') | 230 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 109 nlc = 0; | 231 close(fd); |
| 110 } | 232 g_free(phb->host); |
| 111 | 233 g_free(phb); |
| 112 debug_printf("Proxy says: %s\n", inputline); | 234 return -1; |
| 113 | 235 } |
| 114 if ((memcmp(HTTP_GOODSTRING, inputline, strlen(HTTP_GOODSTRING)) == 0) || | 236 fcntl(fd, F_SETFL, 0); |
| 115 (memcmp(HTTP_GOODSTRING2, inputline, strlen(HTTP_GOODSTRING2)) == 0)) { | 237 http_canwrite(phb, fd, GDK_INPUT_WRITE); |
| 116 return fd; | 238 } |
| 117 } | 239 |
| 118 | 240 return fd; |
| 119 close(fd); | 241 } |
| 120 return -1; | 242 |
| 121 } | 243 static void s4_canread(gpointer data, gint source, GdkInputCondition cond) |
| 122 | 244 { |
| 123 static int proxy_connect_socks4(char *host, unsigned short port, | 245 unsigned char packet[12]; |
| 124 char *proxyhost, unsigned short proxyport) | 246 struct PHB *phb = data; |
| 125 { | 247 |
| 126 struct sockaddr_in sin; | 248 gdk_input_remove(phb->inpa); |
| 249 | |
| 250 memset(packet, 0, sizeof(packet)); | |
| 251 if (read(source, packet, 9) >= 4 && packet[1] == 90) { | |
| 252 phb->func(phb->data, source, GDK_INPUT_READ); | |
| 253 g_free(phb->host); | |
| 254 g_free(phb); | |
| 255 return; | |
| 256 } | |
| 257 | |
| 258 close(source); | |
| 259 phb->func(phb->data, -1, GDK_INPUT_READ); | |
| 260 g_free(phb->host); | |
| 261 g_free(phb); | |
| 262 } | |
| 263 | |
| 264 static void s4_canwrite(gpointer data, gint source, GdkInputCondition cond) | |
| 265 { | |
| 127 unsigned char packet[12]; | 266 unsigned char packet[12]; |
| 128 struct hostent *hp; | 267 struct hostent *hp; |
| 129 int fd = -1; | 268 struct PHB *phb = data; |
| 130 | 269 int len, error = ETIMEDOUT; |
| 131 debug_printf("connecting to %s:%d via %s:%d using SOCKS4\n", host, port, proxyhost, proxyport); | 270 debug_printf("Connected\n"); |
| 132 | 271 if (phb->inpa > 0) |
| 133 if (!(hp = gethostbyname(proxyhost))) | 272 gdk_input_remove(phb->inpa); |
| 134 return -1; | 273 len = sizeof(error); |
| 135 | 274 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { |
| 136 memset(&sin, 0, sizeof(struct sockaddr_in)); | 275 close(source); |
| 137 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); | 276 phb->func(phb->data, -1, GDK_INPUT_READ); |
| 138 sin.sin_family = hp->h_addrtype; | 277 g_free(phb->host); |
| 139 sin.sin_port = htons(proxyport); | 278 g_free(phb); |
| 140 | 279 return; |
| 141 if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) | 280 } |
| 142 return -1; | 281 fcntl(source, F_SETFL, 0); |
| 143 | |
| 144 if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { | |
| 145 close(fd); | |
| 146 return -1; | |
| 147 } | |
| 148 | 282 |
| 149 /* XXX does socks4 not support host name lookups by the proxy? */ | 283 /* XXX does socks4 not support host name lookups by the proxy? */ |
| 150 if (!(hp = gethostbyname(host))) | 284 if (!(hp = gethostbyname(phb->host))) { |
| 151 return -1; | 285 close(source); |
| 286 phb->func(phb->data, -1, GDK_INPUT_READ); | |
| 287 g_free(phb->host); | |
| 288 g_free(phb); | |
| 289 return; | |
| 290 } | |
| 152 | 291 |
| 153 packet[0] = 4; | 292 packet[0] = 4; |
| 154 packet[1] = 1; | 293 packet[1] = 1; |
| 155 packet[2] = port >> 8; | 294 packet[2] = phb->port >> 8; |
| 156 packet[3] = port & 0xff; | 295 packet[3] = phb->port & 0xff; |
| 157 packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; | 296 packet[4] = (unsigned char)(hp->h_addr_list[0])[0]; |
| 158 packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; | 297 packet[5] = (unsigned char)(hp->h_addr_list[0])[1]; |
| 159 packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; | 298 packet[6] = (unsigned char)(hp->h_addr_list[0])[2]; |
| 160 packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; | 299 packet[7] = (unsigned char)(hp->h_addr_list[0])[3]; |
| 161 packet[8] = 0; | 300 packet[8] = 0; |
| 162 if (write(fd, packet, 9) == 9) { | 301 if (write(source, packet, 9) != 9) { |
| 163 memset(packet, 0, sizeof(packet)); | 302 close(source); |
| 164 if (read(fd, packet, 9) >= 4 && packet[1] == 90) | 303 phb->func(phb->data, -1, GDK_INPUT_READ); |
| 165 return fd; | 304 g_free(phb->host); |
| 166 } | 305 g_free(phb); |
| 167 close(fd); | 306 return; |
| 168 | 307 } |
| 169 return -1; | 308 |
| 170 } | 309 phb->inpa = gdk_input_add(source, GDK_INPUT_READ, s4_canread, phb); |
| 171 | 310 } |
| 172 static int proxy_connect_socks5(char *host, unsigned short port, | 311 |
| 173 char *proxyhost, unsigned short proxyport) | 312 static int proxy_connect_socks4(char *host, unsigned short port, |
| 174 { | 313 char *proxyhost, unsigned short proxyport, |
| 175 int i, fd = -1; | 314 struct PHB *phb) |
| 176 unsigned char buf[512]; | 315 { |
| 177 struct sockaddr_in sin; | 316 struct sockaddr_in sin; |
| 178 struct hostent *hp; | 317 struct hostent *hp; |
| 179 int hlen = strlen(host); | 318 int fd = -1; |
| 180 | 319 |
| 181 debug_printf("connecting to %s:%d via %s:%d using SOCKS5\n", host, port, proxyhost, proxyport); | 320 debug_printf("connecting to %s:%d via %s:%d using SOCKS4\n", host, port, proxyhost, proxyport); |
| 182 | 321 |
| 183 if (!(hp = gethostbyname(proxyhost))) | 322 if (!(hp = gethostbyname(proxyhost))) { |
| 184 return -1; | 323 g_free(phb); |
| 324 return -1; | |
| 325 } | |
| 185 | 326 |
| 186 memset(&sin, 0, sizeof(struct sockaddr_in)); | 327 memset(&sin, 0, sizeof(struct sockaddr_in)); |
| 187 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); | 328 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); |
| 188 sin.sin_family = hp->h_addrtype; | 329 sin.sin_family = hp->h_addrtype; |
| 189 sin.sin_port = htons(proxyport); | 330 sin.sin_port = htons(proxyport); |
| 190 | 331 |
| 191 if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) | 332 if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) { |
| 192 return -1; | 333 g_free(phb); |
| 193 | 334 return -1; |
| 335 } | |
| 336 | |
| 337 phb->host = g_strdup(host); | |
| 338 phb->port = port; | |
| 339 | |
| 340 fcntl(fd, F_SETFL, O_NONBLOCK); | |
| 194 if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { | 341 if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { |
| 195 close(fd); | 342 if ((errno == EINPROGRESS) || (errno == EINTR)) { |
| 196 return -1; | 343 debug_printf("Connect would have blocked\n"); |
| 197 } | 344 phb->inpa = gdk_input_add(fd, GDK_INPUT_WRITE, s4_canwrite, phb); |
| 345 } else { | |
| 346 close(fd); | |
| 347 g_free(phb->host); | |
| 348 g_free(phb); | |
| 349 return -1; | |
| 350 } | |
| 351 } else { | |
| 352 int len, error = ETIMEDOUT; | |
| 353 debug_printf("Connect didn't block\n"); | |
| 354 len = sizeof(error); | |
| 355 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | |
| 356 close(fd); | |
| 357 g_free(phb->host); | |
| 358 g_free(phb); | |
| 359 return -1; | |
| 360 } | |
| 361 fcntl(fd, F_SETFL, 0); | |
| 362 s4_canwrite(phb, fd, GDK_INPUT_WRITE); | |
| 363 } | |
| 364 | |
| 365 return fd; | |
| 366 } | |
| 367 | |
| 368 static void s5_canread_again(gpointer data, gint source, GdkInputCondition cond) | |
| 369 { | |
| 370 unsigned char buf[512]; | |
| 371 struct PHB *phb = data; | |
| 372 | |
| 373 gdk_input_remove(phb->inpa); | |
| 374 debug_printf("able to read again\n"); | |
| 375 | |
| 376 if (read(source, buf, 10) < 10) { | |
| 377 debug_printf("or not...\n"); | |
| 378 close(source); | |
| 379 phb->func(phb->data, -1, GDK_INPUT_READ); | |
| 380 g_free(phb->host); | |
| 381 g_free(phb); | |
| 382 return; | |
| 383 } | |
| 384 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { | |
| 385 debug_printf("bad data\n"); | |
| 386 close(source); | |
| 387 phb->func(phb->data, -1, GDK_INPUT_READ); | |
| 388 g_free(phb->host); | |
| 389 g_free(phb); | |
| 390 return; | |
| 391 } | |
| 392 | |
| 393 phb->func(phb->data, source, GDK_INPUT_READ); | |
| 394 g_free(phb->host); | |
| 395 g_free(phb); | |
| 396 return; | |
| 397 } | |
| 398 | |
| 399 static void s5_canread(gpointer data, gint source, GdkInputCondition cond) | |
| 400 { | |
| 401 unsigned char buf[512]; | |
| 402 struct PHB *phb = data; | |
| 403 int hlen = strlen(phb->host); | |
| 404 | |
| 405 gdk_input_remove(phb->inpa); | |
| 406 debug_printf("able to read\n"); | |
| 407 | |
| 408 if (read(source, buf, 2) < 2) { | |
| 409 close(source); | |
| 410 phb->func(phb->data, -1, GDK_INPUT_READ); | |
| 411 g_free(phb->host); | |
| 412 g_free(phb); | |
| 413 return; | |
| 414 } | |
| 415 | |
| 416 if ((buf[0] != 0x05) || (buf[1] == 0xff)) { | |
| 417 close(source); | |
| 418 phb->func(phb->data, -1, GDK_INPUT_READ); | |
| 419 g_free(phb->host); | |
| 420 g_free(phb); | |
| 421 return; | |
| 422 } | |
| 423 | |
| 424 buf[0] = 0x05; | |
| 425 buf[1] = 0x01; /* CONNECT */ | |
| 426 buf[2] = 0x00; /* reserved */ | |
| 427 buf[3] = 0x03; /* address type -- host name */ | |
| 428 buf[4] = hlen; | |
| 429 memcpy(buf + 5, phb->host, hlen); | |
| 430 buf[5 + strlen(phb->host)] = phb->port >> 8; | |
| 431 buf[5 + strlen(phb->host) + 1] = phb->port & 0xff; | |
| 432 | |
| 433 if (write(source, buf, (5 + strlen(phb->host) + 2)) < (5 + strlen(phb->host) + 2)) { | |
| 434 close(source); | |
| 435 phb->func(phb->data, -1, GDK_INPUT_READ); | |
| 436 g_free(phb->host); | |
| 437 g_free(phb); | |
| 438 return; | |
| 439 } | |
| 440 | |
| 441 phb->inpa = gdk_input_add(source, GDK_INPUT_READ, s5_canread_again, phb); | |
| 442 } | |
| 443 | |
| 444 static void s5_canwrite(gpointer data, gint source, GdkInputCondition cond) | |
| 445 { | |
| 446 unsigned char buf[512]; | |
| 447 int i; | |
| 448 struct PHB *phb = data; | |
| 449 int len, error = ETIMEDOUT; | |
| 450 debug_printf("Connected\n"); | |
| 451 if (phb->inpa > 0) | |
| 452 gdk_input_remove(phb->inpa); | |
| 453 len = sizeof(error); | |
| 454 if (getsockopt(source, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | |
| 455 close(source); | |
| 456 phb->func(phb->data, -1, GDK_INPUT_READ); | |
| 457 g_free(phb->host); | |
| 458 g_free(phb); | |
| 459 return; | |
| 460 } | |
| 461 fcntl(source, F_SETFL, 0); | |
| 198 | 462 |
| 199 i = 0; | 463 i = 0; |
| 200 buf[0] = 0x05; /* SOCKS version 5 */ | 464 buf[0] = 0x05; /* SOCKS version 5 */ |
| 201 buf[1] = 0x01; | 465 buf[1] = 0x01; |
| 202 buf[2] = 0x00; | 466 buf[2] = 0x00; |
| 203 i = 3; | 467 i = 3; |
| 204 | 468 |
| 205 if (write(fd, buf, i) < i) { | 469 if (write(source, buf, i) < i) { |
| 206 close(fd); | 470 debug_printf("unable to write\n"); |
| 207 return -1; | 471 close(source); |
| 208 } | 472 phb->func(phb->data, -1, GDK_INPUT_READ); |
| 209 | 473 g_free(phb->host); |
| 210 if (read(fd, buf, 2) < 2) { | 474 g_free(phb); |
| 211 close(fd); | 475 return; |
| 212 return -1; | 476 } |
| 213 } | 477 |
| 214 | 478 phb->inpa = gdk_input_add(source, GDK_INPUT_READ, s5_canread, phb); |
| 215 if ((buf[0] != 0x05) || (buf[1] == 0xff)) { | 479 } |
| 216 close(fd); | 480 |
| 217 return -1; | 481 static int proxy_connect_socks5(char *host, unsigned short port, |
| 218 } | 482 char *proxyhost, unsigned short proxyport, |
| 219 | 483 struct PHB *phb) |
| 220 buf[0] = 0x05; | 484 { |
| 221 buf[1] = 0x01; /* CONNECT */ | 485 int fd = -1; |
| 222 buf[2] = 0x00; /* reserved */ | 486 struct sockaddr_in sin; |
| 223 buf[3] = 0x03; /* address type -- host name */ | 487 struct hostent *hp; |
| 224 buf[4] = hlen; | 488 |
| 225 memcpy(buf + 5, host, hlen); | 489 debug_printf("connecting to %s:%d via %s:%d using SOCKS5\n", host, port, proxyhost, proxyport); |
| 226 buf[5 + strlen(host)] = port >> 8; | 490 |
| 227 buf[5 + strlen(host) + 1] = port & 0xff; | 491 if (!(hp = gethostbyname(proxyhost))) { |
| 228 | 492 g_free(phb); |
| 229 if (write(fd, buf, (5 + strlen(host) + 2)) < (5 + strlen(host) + 2)) { | 493 return -1; |
| 230 close(fd); | 494 } |
| 231 return -1; | 495 |
| 232 } | 496 memset(&sin, 0, sizeof(struct sockaddr_in)); |
| 233 if (read(fd, buf, 10) < 10) { | 497 memcpy(&sin.sin_addr.s_addr, hp->h_addr, hp->h_length); |
| 234 close(fd); | 498 sin.sin_family = hp->h_addrtype; |
| 235 return -1; | 499 sin.sin_port = htons(proxyport); |
| 236 } | 500 |
| 237 if ((buf[0] != 0x05) || (buf[1] != 0x00)) { | 501 if ((fd = socket(hp->h_addrtype, SOCK_STREAM, 0)) < 0) { |
| 238 close(fd); | 502 g_free(phb); |
| 239 return -1; | 503 return -1; |
| 504 } | |
| 505 | |
| 506 phb->host = g_strdup(host); | |
| 507 phb->port = port; | |
| 508 | |
| 509 fcntl(fd, F_SETFL, O_NONBLOCK); | |
| 510 if (connect(fd, (struct sockaddr *)&sin, sizeof(sin)) < 0) { | |
| 511 if ((errno == EINPROGRESS) || (errno == EINTR)) { | |
| 512 debug_printf("Connect would have blocked\n"); | |
| 513 phb->inpa = gdk_input_add(fd, GDK_INPUT_WRITE, s5_canwrite, phb); | |
| 514 } else { | |
| 515 close(fd); | |
| 516 g_free(phb->host); | |
| 517 g_free(phb); | |
| 518 return -1; | |
| 519 } | |
| 520 } else { | |
| 521 int len, error = ETIMEDOUT; | |
| 522 debug_printf("Connect didn't block\n"); | |
| 523 len = sizeof(error); | |
| 524 if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) { | |
| 525 close(fd); | |
| 526 g_free(phb->host); | |
| 527 g_free(phb); | |
| 528 return -1; | |
| 529 } | |
| 530 fcntl(fd, F_SETFL, 0); | |
| 531 s5_canwrite(phb, fd, GDK_INPUT_WRITE); | |
| 240 } | 532 } |
| 241 | 533 |
| 242 return fd; | 534 return fd; |
| 243 } | 535 } |
| 244 | 536 |
| 245 int proxy_connect(char *host, int port, char *proxyhost, int proxyport, int proxytype) | 537 int proxy_connect(char *host, int port, |
| 246 { | 538 char *proxyhost, int proxyport, int proxytype, |
| 247 if (!host || !port || (port == -1)) | 539 GdkInputFunction func, gpointer data) |
| 248 return -1; | 540 { |
| 249 else if ((proxytype == PROXY_NONE) || | 541 struct PHB *phb = g_new0(struct PHB, 1); |
| 542 phb->func = func; | |
| 543 phb->data = data; | |
| 544 | |
| 545 if (!host || !port || (port == -1) || !func) { | |
| 546 g_free(phb); | |
| 547 return -1; | |
| 548 } | |
| 549 | |
| 550 if ((proxytype == PROXY_NONE) || | |
| 250 !proxyhost || !proxyhost[0] || | 551 !proxyhost || !proxyhost[0] || |
| 251 !proxyport || (proxyport == -1)) return proxy_connect_none(host, port); | 552 !proxyport || (proxyport == -1)) |
| 553 return proxy_connect_none(host, port, phb); | |
| 252 else if (proxytype == PROXY_HTTP) | 554 else if (proxytype == PROXY_HTTP) |
| 253 return proxy_connect_http(host, port, proxyhost, proxyport); | 555 return proxy_connect_http(host, port, proxyhost, proxyport, phb); |
| 254 else if (proxytype == PROXY_SOCKS4) | 556 else if (proxytype == PROXY_SOCKS4) |
| 255 return proxy_connect_socks4(host, port, proxyhost, proxyport); | 557 return proxy_connect_socks4(host, port, proxyhost, proxyport, phb); |
| 256 else if (proxytype == PROXY_SOCKS5) | 558 else if (proxytype == PROXY_SOCKS5) |
| 257 return proxy_connect_socks5(host, port, proxyhost, proxyport); | 559 return proxy_connect_socks5(host, port, proxyhost, proxyport, phb); |
| 560 | |
| 561 g_free(phb); | |
| 258 return -1; | 562 return -1; |
| 259 } | 563 } |
