65
65
#include <dirent.h>
66
66
#include <fcntl.h>
67
67
#include <signal.h>
68
+ #include <ctype.h>
68
69
#include <pwd.h>
69
70
#include <grp.h>
70
71
@@ -80,14 +81,20 @@ extern char **environ;
80
81
81
82
#include <process.h>
82
83
#include <windows.h>
84
+ #include <winhttp.h>
83
85
#include <ws2tcpip.h>
84
86
#include <wincrypt.h>
85
87
#include <tlhelp32.h>
86
88
#include <iphlpapi.h>
87
89
#include <shlobj.h>
88
90
91
+ #pragma comment(lib, "winhttp.lib")
92
+
89
93
#endif
90
94
95
+ #define PROXY_NONE 0
96
+ #define PROXY_CONNECT 1
97
+
91
98
typedef struct {
92
99
psync_thread_start0 run ;
93
100
const char * name ;
@@ -106,6 +113,11 @@ static gid_t *psync_gids;
106
113
static int psync_gids_cnt ;
107
114
#endif
108
115
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
+
109
121
static int psync_page_size ;
110
122
111
123
static const char * psync_software_name = "pCloudSync library " PSYNC_LIB_VERSION ;
@@ -1188,7 +1200,100 @@ static void resolve_callback(void *h, void *ptr){
1188
1200
psync_task_complete (h , res );
1189
1201
}
1190
1202
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 ){
1192
1297
struct addrinfo * res , * dbres ;
1193
1298
struct addrinfo hints ;
1194
1299
psync_socket_t sock ;
@@ -1210,6 +1315,7 @@ static psync_socket_t connect_socket(const char *host, const char *port){
1210
1315
res = (struct addrinfo * )psync_task_get_result (tasks , 1 );
1211
1316
if (unlikely (!res )){
1212
1317
psync_task_free (tasks );
1318
+ detect_proxy ();
1213
1319
debug (D_WARNING , "failed to resolve %s" , host );
1214
1320
return INVALID_SOCKET ;
1215
1321
}
@@ -1241,6 +1347,7 @@ static psync_socket_t connect_socket(const char *host, const char *port){
1241
1347
#endif
1242
1348
if (unlikely (rc != 0 )){
1243
1349
debug (D_WARNING , "failed to resolve %s" , host );
1350
+ detect_proxy ();
1244
1351
return INVALID_SOCKET ;
1245
1352
}
1246
1353
addr_save_to_db (host , port , res );
@@ -1274,11 +1381,111 @@ static psync_socket_t connect_socket(const char *host, const char *port){
1274
1381
#endif
1275
1382
#endif
1276
1383
}
1277
- else
1384
+ else {
1385
+ detect_proxy ();
1278
1386
debug (D_WARNING , "failed to connect to %s:%s" , host , port );
1387
+ }
1279
1388
return sock ;
1280
1389
}
1281
1390
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
+
1282
1489
static int wait_sock_ready_for_ssl (psync_socket_t sock ){
1283
1490
fd_set fds , * rfds , * wfds ;
1284
1491
struct timeval tv ;
0 commit comments