Skip to content

Commit 57f5867

Browse files
author
virco
committed
proxy auto-detection and use for Windows
1 parent 30a2189 commit 57f5867

File tree

2 files changed

+212
-5
lines changed

2 files changed

+212
-5
lines changed

gitcommit.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#ifndef _GITCOMMIT_H
22
#define _GITCOMMIT_H
33

4-
#define GIT_PREV_COMMIT_ID "f7113c6d269d4782c45d6a116faf113e3ea2a110"
5-
#define GIT_PREV_COMMIT_DATE "2016-12-20 15:50:08 +0200"
6-
#define GIT_COMMIT_DATE "2016-12-20 16:50:54 +0200"
4+
#define GIT_PREV_COMMIT_ID "30a21899d4ab26b42c021ec3048881c8d1fa240d"
5+
#define GIT_PREV_COMMIT_DATE "2016-12-20 16:50:54 +0200"
6+
#define GIT_COMMIT_DATE "2016-12-21 17:40:55 +0200"
77

88
#endif

pcompat.c

Lines changed: 209 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
#include <dirent.h>
6666
#include <fcntl.h>
6767
#include <signal.h>
68+
#include <ctype.h>
6869
#include <pwd.h>
6970
#include <grp.h>
7071

@@ -80,14 +81,20 @@ extern char **environ;
8081

8182
#include <process.h>
8283
#include <windows.h>
84+
#include <winhttp.h>
8385
#include <ws2tcpip.h>
8486
#include <wincrypt.h>
8587
#include <tlhelp32.h>
8688
#include <iphlpapi.h>
8789
#include <shlobj.h>
8890

91+
#pragma comment(lib, "winhttp.lib")
92+
8993
#endif
9094

95+
#define PROXY_NONE 0
96+
#define PROXY_CONNECT 1
97+
9198
typedef struct {
9299
psync_thread_start0 run;
93100
const char *name;
@@ -106,6 +113,11 @@ static gid_t *psync_gids;
106113
static int psync_gids_cnt;
107114
#endif
108115

116+
static int proxy_type=PROXY_NONE;
117+
static int proxy_detected=0;
118+
static char proxy_host[256];
119+
static char proxy_port[8];
120+
109121
static int psync_page_size;
110122

111123
static const char *psync_software_name="pCloudSync library "PSYNC_LIB_VERSION;
@@ -1188,7 +1200,100 @@ static void resolve_callback(void *h, void *ptr){
11881200
psync_task_complete(h, res);
11891201
}
11901202

1191-
static psync_socket_t connect_socket(const char *host, const char *port){
1203+
#if defined(P_OS_WINDOWS)
1204+
static void gfree_ptr(HGLOBAL ptr){
1205+
if (ptr!=NULL)
1206+
GlobalFree(ptr);
1207+
}
1208+
1209+
static int try_set_proxy(LPWSTR pstr){
1210+
char *str, *c;
1211+
size_t hl, pl;
1212+
if (!pstr)
1213+
return 0;
1214+
str=wchar_to_utf8(pstr);
1215+
c=strchr(str, ':');
1216+
if (!c)
1217+
goto err;
1218+
hl=c-str;
1219+
c++;
1220+
pl=strlen(c);
1221+
if (pl && hl && hl<sizeof(proxy_host) && pl<sizeof(proxy_port)) {
1222+
proxy_host[hl]=0;
1223+
memcpy(proxy_host, str, hl);
1224+
proxy_port[pl]=0;
1225+
memcpy(proxy_port, c, pl);
1226+
psync_free(str);
1227+
proxy_type=PROXY_CONNECT;
1228+
debug(D_NOTICE, "auto detected proxy %s:%s", proxy_host, proxy_port);
1229+
return 1;
1230+
}
1231+
err:
1232+
psync_free(str);
1233+
return 0;
1234+
}
1235+
1236+
#define PSYNC_HAS_PROXY_CODE
1237+
1238+
#endif
1239+
1240+
#if defined(PSYNC_HAS_PROXY_CODE)
1241+
static int recent_detect(){
1242+
static time_t lastdetect=0;
1243+
if (psync_timer_time()<lastdetect+60)
1244+
return 1;
1245+
else{
1246+
lastdetect=psync_timer_time();
1247+
return 0;
1248+
}
1249+
}
1250+
#endif
1251+
1252+
static void detect_proxy(){
1253+
#if defined(P_OS_WINDOWS)
1254+
WINHTTP_CURRENT_USER_IE_PROXY_CONFIG ieconf;
1255+
WINHTTP_AUTOPROXY_OPTIONS aopt;
1256+
WINHTTP_PROXY_INFO pinfo;
1257+
HINTERNET hi;
1258+
if (recent_detect())
1259+
return;
1260+
hi=NULL;
1261+
pinfo.lpszProxy=NULL;
1262+
pinfo.lpszProxyBypass=NULL;
1263+
if (!WinHttpGetIEProxyConfigForCurrentUser(&ieconf))
1264+
return;
1265+
if (ieconf.fAutoDetect){
1266+
hi=WinHttpOpen(L"pCloud", WINHTTP_ACCESS_TYPE_DEFAULT_PROXY, WINHTTP_NO_PROXY_NAME, WINHTTP_NO_PROXY_BYPASS, 0);
1267+
if (!hi){
1268+
debug(D_NOTICE, "WinHttpOpen failed");
1269+
goto manual;
1270+
}
1271+
memset(aopt, 0, sizeof(aopt));
1272+
aopt.dwFlags=WINHTTP_AUTOPROXY_AUTO_DETECT;
1273+
aopt.dwAutoDetectFlags=WINHTTP_AUTO_DETECT_TYPE_DHCP|WINHTTP_AUTO_DETECT_TYPE_DNS_A;
1274+
if (ieconf.lpszAutoConfigUrl){
1275+
aopt.dwFlags|=WINHTTP_AUTOPROXY_CONFIG_URL;
1276+
aopt.lpszAutoConfigUrl=ieconf.lpszAutoConfigUrl;
1277+
}
1278+
aopt.fAutoLogonIfChallenged=TRUE;
1279+
if (WinHttpGetProxyForUrl(hi, L"https://api.pcloud.com/", &aopt, &pinfo) && pinfo.dwAccessType==WINHTTP_ACCESS_TYPE_NAMED_PROXY &&
1280+
try_set_proxy(pinfo.lpszProxy))
1281+
goto ex;
1282+
}
1283+
manual:
1284+
try_set_proxy(pinfo.lpszProxy);
1285+
ex:
1286+
if (hi)
1287+
WinHttpCloseHandle(hi);
1288+
gfree_ptr(pinfo.lpszProxy);
1289+
gfree_ptr(pinfo.lpszProxyBypass);
1290+
gfree_ptr(ieconf.lpszProxy);
1291+
gfree_ptr(ieconf.lpszProxyBypass);
1292+
gfree_ptr(ieconf.lpszAutoConfigUrl);
1293+
#endif
1294+
}
1295+
1296+
static psync_socket_t connect_socket_direct(const char *host, const char *port){
11921297
struct addrinfo *res, *dbres;
11931298
struct addrinfo hints;
11941299
psync_socket_t sock;
@@ -1210,6 +1315,7 @@ static psync_socket_t connect_socket(const char *host, const char *port){
12101315
res=(struct addrinfo *)psync_task_get_result(tasks, 1);
12111316
if (unlikely(!res)){
12121317
psync_task_free(tasks);
1318+
detect_proxy();
12131319
debug(D_WARNING, "failed to resolve %s", host);
12141320
return INVALID_SOCKET;
12151321
}
@@ -1241,6 +1347,7 @@ static psync_socket_t connect_socket(const char *host, const char *port){
12411347
#endif
12421348
if (unlikely(rc!=0)){
12431349
debug(D_WARNING, "failed to resolve %s", host);
1350+
detect_proxy();
12441351
return INVALID_SOCKET;
12451352
}
12461353
addr_save_to_db(host, port, res);
@@ -1274,11 +1381,111 @@ static psync_socket_t connect_socket(const char *host, const char *port){
12741381
#endif
12751382
#endif
12761383
}
1277-
else
1384+
else{
1385+
detect_proxy();
12781386
debug(D_WARNING, "failed to connect to %s:%s", host, port);
1387+
}
12791388
return sock;
12801389
}
12811390

1391+
static int check_http_resp(char *str) {
1392+
if (memcmp(str, "HTTP", 4)){
1393+
debug(D_WARNING, "bad proxy response %s", str);
1394+
return 0;
1395+
}
1396+
while (*str && !isspace(*str))
1397+
str++;
1398+
while (*str && isspace(*str))
1399+
str++;
1400+
if (!isdigit(*str)){
1401+
debug(D_WARNING, "bad proxy response %s", str);
1402+
return 0;
1403+
}
1404+
if (atoi(str)!=200) {
1405+
debug(D_NOTICE, "proxy returned HTTP code %d", atoi(str));
1406+
return 0;
1407+
}
1408+
return 1;
1409+
}
1410+
1411+
static psync_socket_t connect_socket_connect_proxy(const char *host, const char *port){
1412+
char buff[2048], *str;
1413+
psync_socket_t sock;
1414+
int ln, wr, r, rc;
1415+
sock=connect_socket_direct(proxy_host, proxy_port);
1416+
if (unlikely(sock==INVALID_SOCKET)){
1417+
debug(D_NOTICE, "connection to proxy %s:%s failed", proxy_host, proxy_port);
1418+
goto err0;
1419+
}
1420+
ln=psync_slprintf(buff, sizeof(buff), "CONNECT %s:%s HTTP/1.0\015\012User-Agent: %s\015\012\015\012", host, port, psync_software_name);
1421+
wr=0;
1422+
while (wr<ln){
1423+
r=psync_write_socket(sock, buff+wr, ln-wr);
1424+
if (unlikely(r==SOCKET_ERROR)){
1425+
if (likely_log((psync_sock_err()==P_WOULDBLOCK || psync_sock_err()==P_AGAIN || psync_sock_err()==P_INTR) && !psync_wait_socket_write_timeout(sock)))
1426+
continue;
1427+
else
1428+
goto err1;
1429+
}
1430+
wr+=r;
1431+
}
1432+
wr=0;
1433+
rc=0;
1434+
while (1){
1435+
if (unlikely(psync_wait_socket_read_timeout(sock))){
1436+
debug(D_WARNING, "connection to %s:%s via %s:%s timeouted", host, port, proxy_host, proxy_port);
1437+
goto err1;
1438+
}
1439+
r=psync_read_socket(sock, buff+wr, sizeof(buff)-1-wr);
1440+
if (unlikely(r==0 || r==SOCKET_ERROR)){
1441+
if (r==0){
1442+
debug(D_NOTICE, "proxy server %s:%s closed connection", proxy_host, proxy_port);
1443+
goto err1;
1444+
}
1445+
if (likely_log(psync_sock_err()==P_WOULDBLOCK || psync_sock_err()==P_AGAIN || psync_sock_err()==P_INTR))
1446+
continue;
1447+
else
1448+
goto err1;
1449+
}
1450+
wr+=r;
1451+
buff[wr]=0;
1452+
str=strstr(buff, "\015\012\015\012");
1453+
if (str){
1454+
if (rc || check_http_resp(buff)){
1455+
debug(D_NOTICE, "connected to %s:%s via %s:%s", host, port, proxy_host, proxy_port);
1456+
return sock;
1457+
}else
1458+
goto err1;
1459+
}
1460+
if (wr==sizeof(buff)-1){
1461+
rc=check_http_resp(buff);
1462+
if (!rc)
1463+
goto err1;
1464+
memcpy(buff, buff+sizeof(buff)-8, 8);
1465+
wr=7; // yes, 7
1466+
}
1467+
}
1468+
err1:
1469+
psync_close_socket(sock);
1470+
err0:
1471+
detect_proxy();
1472+
if (proxy_type!=PROXY_CONNECT)
1473+
return connect_socket_direct(host, port);
1474+
else
1475+
return INVALID_SOCKET;
1476+
}
1477+
1478+
static psync_socket_t connect_socket(const char *host, const char *port){
1479+
if (unlikely(!proxy_detected)){
1480+
proxy_detected=1;
1481+
detect_proxy();
1482+
}
1483+
if (likely(proxy_type!=PROXY_CONNECT))
1484+
return connect_socket_direct(host, port);
1485+
else
1486+
return connect_socket_connect_proxy(host, port);
1487+
}
1488+
12821489
static int wait_sock_ready_for_ssl(psync_socket_t sock){
12831490
fd_set fds, *rfds, *wfds;
12841491
struct timeval tv;

0 commit comments

Comments
 (0)