main.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. #include <string>
  2. #include <vector>
  3. #include <map>
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <stdarg.h>
  8. #ifdef _WIN32
  9. #include <winsock2.h>
  10. #include <ws2tcpip.h>
  11. #include <mswsock.h>
  12. #else
  13. #include <sys/socket.h>
  14. #include <netinet/in.h>
  15. #include <netdb.h>
  16. #endif
  17. #include <pthread.h>
  18. #include <signal.h>
  19. #include <getopt.h>
  20. #include <curl/curl.h>
  21. #ifdef USE_LUA
  22. #include <lua.hpp>
  23. #endif
  24. #include "BBS2chProxyConnection.h"
  25. #include "BBS2chProxyThreadInfo.h"
  26. #include "BBS2chProxyAuth.h"
  27. #ifdef USE_MITM
  28. #include "BBS2chProxySecureSocket.h"
  29. #endif
  30. #define PORT 9080
  31. #define VERSION "20220415"
  32. #define BACKLOG 32
  33. #define NUM_LOCKS 7
  34. char *proxy_server;
  35. long proxy_port;
  36. long proxy_type;
  37. long timeout = 30;
  38. char *user_agent;
  39. char *appKey;
  40. char *hmacKey;
  41. char *api_ua_auth;
  42. char *api_ua_dat;
  43. char *x_2ch_ua_auth;
  44. char *x_2ch_ua_dat;
  45. int allow_chunked;
  46. int verbosity;
  47. int curl_features;
  48. unsigned int curl_version_number;
  49. bool accept_https;
  50. int force_5chnet = 1;
  51. int force_5chnet_https;
  52. int force_ipv4;
  53. char *bbsmenu_url;
  54. char *api_server;
  55. std::map<std::string, std::string> bbscgi_headers;
  56. int gikofix;
  57. CURLSH *curl_share;
  58. char *lua_script;
  59. unsigned int api_mode = 3;
  60. unsigned int mitm_mode = 0;
  61. std::vector<std::string> bbscgi_postorder;
  62. unsigned int bbscgi_utf8 = 1;
  63. static pthread_mutex_t lockarray[NUM_LOCKS];
  64. void log_printf(int level, const char *format ...)
  65. {
  66. if(level > verbosity) return;
  67. va_list argp;
  68. va_start(argp, format);
  69. vfprintf(stderr, format, argp);
  70. va_end(argp);
  71. fflush(stderr);
  72. }
  73. struct listener {
  74. int port;
  75. int sock_listener;
  76. struct sockaddr_in addr_listener;
  77. };
  78. static void usage(void)
  79. {
  80. fprintf(stderr,"usage: proxy2ch [OPTIONS]\n");
  81. fprintf(stderr,"available options:\n");
  82. fprintf(stderr," -p <port> : Listen on port <port> (default: %d)\n",PORT);
  83. fprintf(stderr," -t <timeout> : Set connection timeout to <timeout> seconds (default: %ld)\n",timeout);
  84. fprintf(stderr," -a <user-agent> : Overwrite user-agent for connection\n");
  85. fprintf(stderr," -g : Accept all incoming connections (default: localhost only)\n");
  86. fprintf(stderr," -c : Accept HTTP CONNECT method (act as an HTTPS proxy)\n");
  87. fprintf(stderr," -4 : Force IPv4 DNS resolution\n");
  88. fprintf(stderr," -b <backlog> : Set backlog value to <backlog> for listen() (default: %d)\n",BACKLOG);
  89. fprintf(stderr," -s : Force https connection for 5ch.net/bbspink.com URLs\n");
  90. fprintf(stderr," --proxy <server:port> : Use proxy <server:port> for connection\n");
  91. fprintf(stderr," --api <AppKey:HmacKey> : Use API for reading/posting\n");
  92. fprintf(stderr," --api-usage <read|post|all> : Specify operations where API is used (default: all)\n");
  93. fprintf(stderr," --api-auth-ua <user-agent> : Specify user-agent for API authentication\n");
  94. fprintf(stderr," --api-dat-ua <user-agent> : Specify user-agent for dat retrieving via API\n");
  95. fprintf(stderr," --api-auth-xua <X-2ch-UA> : Specify X-2ch-UA for API authentication\n");
  96. fprintf(stderr," --api-dat-xua <X-2ch-UA> : Specify X-2ch-UA for dat retrieving via API\n");
  97. fprintf(stderr," --api-server <server> : Specify gateway server for API\n");
  98. fprintf(stderr," --bbsmenu <URL> : Replace \"5ch.net\" occurrences in links for URL\n");
  99. fprintf(stderr," --chunked : Preserve \"chunked\" transfer encoding\n");
  100. fprintf(stderr," --bbscgi-header <header: value> : Force replace header when sending request to bbs.cgi\n");
  101. fprintf(stderr," --bbscgi-postorder <field1,field2,...> : Specify a field order in request body being sent to bbs.cgi\n");
  102. fprintf(stderr," --bbscgi-utf8 <none|api|all> : Specify whether a request body being sent to bbs.cgi should be converted to UTF-8\n");
  103. #ifdef USE_LUA
  104. fprintf(stderr," --bbscgi-lua <path> : Process request header/body being sent to bbs.cgi with a Lua script at <path>\n");
  105. #endif
  106. fprintf(stderr," --verbose : Print logs in detail\n");
  107. fprintf(stderr," --gikofix : Fix invalid HTTP POST body (for gikoNavi)\n");
  108. #ifdef USE_MITM
  109. fprintf(stderr," --mitm <minimal|all> : Act as MITM proxy when -c option is given (experimental)\n");
  110. fprintf(stderr," --mitm-ca-cert <certpath> : Specify CA certificate in PEM format for MITM proxy\n");
  111. fprintf(stderr," --mitm-ca-key <keypath> : Specify CA private key in PEM format for MITM proxy\n");
  112. fprintf(stderr," --mitm-certgen : Generate self-signed CA certificate and private key, print them in PEM format, and exit\n");
  113. #endif
  114. }
  115. static void *listen(void *param)
  116. {
  117. struct listener *listener = (struct listener *)param;
  118. log_printf(0,"Listening on port %d...\n",listener->port);
  119. if(listener->addr_listener.sin_addr.s_addr == INADDR_ANY) {
  120. log_printf(0,"WARNING: proxy accepts all incoming connections!\n");
  121. }
  122. fflush(stderr);
  123. int sock_c;
  124. pthread_mutex_t mutex, mutex2;
  125. BBS2chProxyThreadCache *cache = new BBS2chProxyThreadCache();
  126. socklen_t addrlen = sizeof(listener->addr_listener);
  127. pthread_mutex_init(&mutex, NULL);
  128. pthread_mutex_init(&mutex2, NULL);
  129. BBS2chProxyAuth *auth = new BBS2chProxyAuth(&mutex2);
  130. while(1) {
  131. if (-1 == (sock_c = accept(listener->sock_listener, (struct sockaddr *)&listener->addr_listener, &addrlen))) {
  132. perror("accept");
  133. continue;
  134. }
  135. //fprintf(stderr,"accepted\n");
  136. BBS2chProxyConnection *connection = new BBS2chProxyConnection(sock_c, cache, auth, &mutex);
  137. connection->run();
  138. }
  139. pthread_mutex_destroy(&mutex);
  140. pthread_mutex_destroy(&mutex2);
  141. delete cache;
  142. }
  143. static void lock_cb(CURL *handle, curl_lock_data data, curl_lock_access access, void *userptr)
  144. {
  145. pthread_mutex_lock(&lockarray[data]);
  146. }
  147. static void unlock_cb(CURL *handle, curl_lock_data data, void *userptr)
  148. {
  149. pthread_mutex_unlock(&lockarray[data]);
  150. }
  151. static void init_locks(void)
  152. {
  153. int i;
  154. for(i = 0; i< NUM_LOCKS; i++)
  155. pthread_mutex_init(&lockarray[i], NULL);
  156. }
  157. int main(int argc, char *argv[])
  158. {
  159. struct listener listener;
  160. int ch;
  161. extern char *optarg;
  162. extern int optind, opterr;
  163. int option_index;
  164. bool global = false;
  165. int backlog = BACKLOG;
  166. const char *certpath = NULL, *keypath = NULL;
  167. struct option options[] = {
  168. {"proxy", 1, NULL, 0},
  169. {"api", 1, NULL, 0},
  170. {"api-auth-ua", 1, NULL, 0},
  171. {"api-dat-ua", 1, NULL, 0},
  172. {"api-auth-xua", 1, NULL, 0},
  173. {"api-dat-xua", 1, NULL, 0},
  174. {"api-server", 1, NULL, 0},
  175. {"api-usage", 1, NULL, 0},
  176. {"bbsmenu", 1, NULL, 0},
  177. {"chunked", 0, NULL, 0},
  178. {"verbose", 0, NULL, 0},
  179. {"debug", 0, NULL, 0},
  180. {"bbscgi-header", 1, NULL, 0},
  181. {"bbscgi-postorder", 1, NULL, 0},
  182. {"bbscgi-utf8", 1, NULL, 0},
  183. #ifdef USE_LUA
  184. {"bbscgi-lua", 1, NULL, 0},
  185. #endif
  186. {"gikofix", 0, NULL, 0},
  187. #ifdef USE_MITM
  188. {"mitm", 1, NULL, 0},
  189. {"mitm-ca-cert", 1, NULL, 0},
  190. {"mitm-ca-key", 1, NULL, 0},
  191. {"mitm-certgen", 0, NULL, 0},
  192. #endif
  193. {0, 0, 0, 0}
  194. };
  195. curl_global_init(CURL_GLOBAL_DEFAULT);
  196. curl_version_info_data *data = curl_version_info(CURLVERSION_NOW);
  197. curl_features = data->features;
  198. curl_version_number = data->version_num;
  199. if(data->version_num >= 0x074400) { /* version 7.68.0 or later */
  200. init_locks();
  201. curl_share = curl_share_init();
  202. curl_share_setopt(curl_share, CURLSHOPT_LOCKFUNC, lock_cb);
  203. curl_share_setopt(curl_share, CURLSHOPT_UNLOCKFUNC, unlock_cb);
  204. curl_share_setopt(curl_share, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS);
  205. #if LIBCURL_VERSION_NUM >= 0x070a03
  206. curl_share_setopt(curl_share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION);
  207. #endif
  208. /* Shared connection cache is still buggy at the moment!
  209. See https://github.com/curl/curl/issues/4915 */
  210. #if 0 && LIBCURL_VERSION_NUM >= 0x073900
  211. curl_share_setopt(curl_share, CURLSHOPT_SHARE, CURL_LOCK_DATA_CONNECT);
  212. #endif
  213. }
  214. log_printf(0,"proxy2ch version %s with curl %s (TLS/SSL backend: %s)\n",VERSION,data->version,data->ssl_version);
  215. #ifdef USE_LUA
  216. log_printf(0,"Scripting enabled with " LUA_RELEASE "\n");
  217. #endif
  218. memset(&listener, 0, sizeof(listener));
  219. listener.port = PORT;
  220. api_server = strdup("api.5ch.net");
  221. while ((ch = getopt_long(argc, argv, "p:t:ha:gc4b:s", options, &option_index)) != -1) {
  222. switch (ch) {
  223. case 0:
  224. if(!strcmp(options[option_index].name, "proxy")) {
  225. char *ptr = strchr(optarg, '@');
  226. if(!ptr) {
  227. ptr = strstr(optarg, "://");
  228. if(ptr) ptr = strchr(ptr+3,':');
  229. else ptr = strchr(optarg,':');
  230. }
  231. else ptr = strchr(ptr+1,':');
  232. if(!ptr) {
  233. fprintf(stderr,"Proxy port is not specified, as --proxy=server:port\n");
  234. return -1;
  235. }
  236. proxy_server = (char *)malloc(ptr-optarg+1);
  237. proxy_port = atoi(ptr+1);
  238. memcpy(proxy_server,optarg,ptr-optarg);
  239. proxy_server[ptr-optarg] = 0;
  240. if(!strncasecmp(optarg,"socks4://",9)) proxy_type = CURLPROXY_SOCKS4;
  241. else if(!strncasecmp(optarg,"socks5://",9)) proxy_type = CURLPROXY_SOCKS5;
  242. #if LIBCURL_VERSION_NUM >= 0x071200
  243. else if(!strncasecmp(optarg,"socks4a://",10)) proxy_type = CURLPROXY_SOCKS4A;
  244. else if(!strncasecmp(optarg,"socks5h://",10)) proxy_type = CURLPROXY_SOCKS5_HOSTNAME;
  245. #endif
  246. }
  247. else if(!strcmp(options[option_index].name, "api")) {
  248. if((curl_features & CURL_VERSION_SSL) == 0) {
  249. fprintf(stderr,"Your libcurl doesn't support HTTPS; API mode cannot be enabled.\n");
  250. return -1;
  251. }
  252. char *ptr = strchr(optarg, ':');
  253. if(!ptr) {
  254. fprintf(stderr,"API keys should be provided as AppKey:HmacKey\n");
  255. return -1;
  256. }
  257. appKey = (char *)malloc(ptr-optarg+1);
  258. memcpy(appKey,optarg,ptr-optarg);
  259. appKey[ptr-optarg] = 0;
  260. char *start = ptr+1;
  261. ptr = strchr(start, ':');
  262. if(!ptr) ptr = strchr(optarg, 0);
  263. hmacKey = (char *)malloc(ptr-start+1);
  264. memcpy(hmacKey,start,ptr-start);
  265. hmacKey[ptr-start] = 0;
  266. /*if(*ptr) {
  267. x_2ch_ua = (char *)malloc(strlen(ptr+1)+11);
  268. sprintf(x_2ch_ua,"X-2ch-UA: %s",ptr+1);
  269. }*/
  270. //fprintf(stderr,"%s,%s,%s\n",appKey,hmacKey,x_2ch_ua);
  271. //return 0;
  272. }
  273. else if(!strcmp(options[option_index].name, "api-auth-ua")) {
  274. api_ua_auth = (char *)malloc(strlen(optarg)+1);
  275. strcpy(api_ua_auth,optarg);
  276. }
  277. else if(!strcmp(options[option_index].name, "api-dat-ua")) {
  278. api_ua_dat = (char *)malloc(strlen(optarg)+1);
  279. strcpy(api_ua_dat,optarg);
  280. }
  281. else if(!strcmp(options[option_index].name, "api-auth-xua")) {
  282. x_2ch_ua_auth = (char *)malloc(strlen(optarg)+11);
  283. sprintf(x_2ch_ua_auth,"X-2ch-UA: %s",optarg);
  284. }
  285. else if(!strcmp(options[option_index].name, "api-dat-xua")) {
  286. x_2ch_ua_dat = (char *)malloc(strlen(optarg)+11);
  287. sprintf(x_2ch_ua_dat,"X-2ch-UA: %s",optarg);
  288. }
  289. else if(!strcmp(options[option_index].name, "chunked")) {
  290. allow_chunked = 1;
  291. }
  292. else if(!strcmp(options[option_index].name, "verbose")) {
  293. verbosity = 1;
  294. }
  295. else if(!strcmp(options[option_index].name, "debug")) {
  296. verbosity = 5;
  297. }
  298. else if(!strcmp(options[option_index].name, "bbsmenu")) {
  299. bbsmenu_url = (char *)malloc(strlen(optarg)+1);
  300. strcpy(bbsmenu_url, optarg);
  301. }
  302. else if(!strcmp(options[option_index].name, "api-server")) {
  303. if(api_server) free(api_server);
  304. api_server = (char *)malloc(strlen(optarg)+1);
  305. strcpy(api_server, optarg);
  306. }
  307. else if(!strcmp(options[option_index].name, "bbscgi-header")) {
  308. char *ptr = strchr(optarg, ':');
  309. if(!ptr) break;
  310. char *header = (char *)malloc(ptr-optarg+1);
  311. memcpy(header,optarg,ptr-optarg);
  312. header[ptr-optarg] = 0;
  313. char *value = ptr+1;
  314. ptr = header+(ptr-optarg-1);
  315. while(*ptr == ' ') *ptr-- = 0;
  316. while(*value == ' ') value++;
  317. bbscgi_headers[header] = value;
  318. free(header);
  319. }
  320. else if(!strcmp(options[option_index].name, "bbscgi-postorder")) {
  321. const char *ptr = optarg;
  322. while(*ptr == ' ') ptr++;
  323. while(*ptr) {
  324. const char *end = strchr(ptr, ',');
  325. if(end) {
  326. const char *next = end + 1;
  327. if(end > ptr) {
  328. end--;
  329. while(*end == ' ' && end > ptr) end--;
  330. bbscgi_postorder.push_back(std::string(ptr, end-ptr+1));
  331. }
  332. ptr = next;
  333. while(*ptr == ' ') ptr++;
  334. continue;
  335. }
  336. end = strchr(ptr, 0);
  337. while(*end == ' ' && end > ptr) end--;
  338. if(end > ptr) bbscgi_postorder.push_back(std::string(ptr, end-ptr));
  339. break;
  340. }
  341. }
  342. else if(!strcmp(options[option_index].name, "bbscgi-utf8")) {
  343. if(!strcmp(optarg, "none")) bbscgi_utf8 = 0;
  344. else if(!strcmp(optarg, "api")) bbscgi_utf8 = 1;
  345. else if(!strcmp(optarg, "all")) bbscgi_utf8 = 2;
  346. else {
  347. fprintf(stderr, "A value for --bbscgi-utf8 must be one of [none, api, all]\n");
  348. return -1;
  349. }
  350. }
  351. #ifdef USE_LUA
  352. else if(!strcmp(options[option_index].name, "bbscgi-lua")) {
  353. lua_script = (char *)malloc(strlen(optarg)+1);
  354. strcpy(lua_script, optarg);
  355. }
  356. #endif
  357. else if(!strcmp(options[option_index].name, "gikofix")) {
  358. gikofix = 1;
  359. }
  360. else if(!strcmp(options[option_index].name, "api-usage")) {
  361. if(!strcmp(optarg, "read")) api_mode = 1;
  362. else if(!strcmp(optarg, "post")) api_mode = 2;
  363. else if(!strcmp(optarg, "postinclpink")) api_mode = 4;
  364. else if(!strcmp(optarg, "all")) api_mode = 3;
  365. else if(!strcmp(optarg, "allinclpink")) api_mode = 5;
  366. else {
  367. fprintf(stderr, "A value for --api-usage must be one of [read, post, postinclpink, all, allinclpink]\n");
  368. return -1;
  369. }
  370. }
  371. #ifdef USE_MITM
  372. else if(!strcmp(options[option_index].name, "mitm")) {
  373. if(!strcmp(optarg, "minimal")) mitm_mode = 1;
  374. else if(!strcmp(optarg, "all")) mitm_mode = 2;
  375. else {
  376. fprintf(stderr, "A value for --mitm must be one of [minimal, all]\n");
  377. return -1;
  378. }
  379. }
  380. else if(!strcmp(options[option_index].name, "mitm-ca-cert")) {
  381. certpath = optarg;
  382. }
  383. else if(!strcmp(options[option_index].name, "mitm-ca-key")) {
  384. keypath = optarg;
  385. }
  386. else if(!strcmp(options[option_index].name, "mitm-certgen")) {
  387. BBS2chProxySecureSocket::generateAndPrintSelfSignedCertificate();
  388. return 0;
  389. }
  390. #endif
  391. break;
  392. case 'p':
  393. listener.port = atoi(optarg);
  394. break;
  395. case 't':
  396. timeout = atoi(optarg);
  397. break;
  398. case 'a':
  399. user_agent = (char *)malloc(strlen(optarg)+1);
  400. strcpy(user_agent, optarg);
  401. break;
  402. case 'g':
  403. global = true;
  404. break;
  405. case 'c':
  406. accept_https = true;
  407. break;
  408. case '4':
  409. force_ipv4 = 1;
  410. break;
  411. case 'b':
  412. backlog = atoi(optarg);
  413. break;
  414. case 's':
  415. if((curl_features & CURL_VERSION_SSL) == 0) {
  416. fprintf(stderr,"Your libcurl doesn't support HTTPS; it does not work with -s option.\n");
  417. return -1;
  418. }
  419. if(strstr(data->ssl_version, "OpenSSL/0") || strstr(data->ssl_version, "OpenSSL/1.0") ||
  420. (strstr(data->ssl_version, "LibreSSL/2") && !strstr(data->ssl_version, "LibreSSL/2.9"))) {
  421. fprintf(stderr,
  422. "WARNING: OpenSSL < 1.1.0 and LibreSSL < 2.9.0 aren't thread-safe without setting callbacks for mutex. "
  423. "It may cause unintended crashes when many requests are incoming at the same time.\n");
  424. }
  425. force_5chnet_https = 1;
  426. break;
  427. default:
  428. usage();
  429. return 0;
  430. }
  431. }
  432. #ifdef USE_MITM
  433. if (mitm_mode) {
  434. if (!certpath || !keypath) {
  435. fprintf(stderr, "MITM is enabled but certificate and/or key is not given.\n");
  436. return -1;
  437. }
  438. if (BBS2chProxySecureSocket::initializeCerts(certpath, keypath) != 0) {
  439. fprintf(stderr, "MITM is enabled but given certificate and/or key is invalid.\n");
  440. return -1;
  441. }
  442. if (!accept_https) {
  443. fprintf(stderr, "WARNING: --mitm option is given but -c is not given. MITM mode is disabled.\n");
  444. }
  445. }
  446. #endif
  447. log_printf(0, "Global User-Agent: %s\n",user_agent?user_agent:"n/a");
  448. if(appKey) {
  449. log_printf(0, "Use API for:");
  450. if (api_mode & 1) log_printf(0, " reading");
  451. if (api_mode & 2) log_printf(0, " posting");
  452. if (api_mode & 4) log_printf(0, " posting (including bbspink)");
  453. log_printf(0, "\n");
  454. if (api_mode & 1) {
  455. log_printf(0, "API gateway server: %s\n",api_server);
  456. log_printf(0, "User-Agent (for API authentication): %s\n",api_ua_auth?api_ua_auth:"");
  457. log_printf(0, "User-Agent (for API dat retrieving): %s\n",api_ua_dat?api_ua_dat:"");
  458. log_printf(0, "X-2ch-UA (for API authentication): %s\n",x_2ch_ua_auth?x_2ch_ua_auth+10:"");
  459. log_printf(0, "X-2ch-UA (for API dat retrieving): %s\n",x_2ch_ua_dat?x_2ch_ua_dat+10:"");
  460. }
  461. }
  462. if(!bbscgi_headers.empty()) {
  463. log_printf(0, "Custom headers for bbs.cgi:\n");
  464. for(std::map<std::string, std::string>::iterator it = bbscgi_headers.begin(); it!=bbscgi_headers.end(); it++) {
  465. log_printf(0, " %s: %s\n", it->first.c_str(), it->second.c_str());
  466. }
  467. }
  468. if(lua_script) {
  469. log_printf(0, "Use Lua script %s for bbs.cgi request modification\n", lua_script);
  470. }
  471. if(proxy_server) {
  472. log_printf(0,"Use proxy %s:%ld for connection\n",proxy_server,proxy_port);
  473. }
  474. BBS2chProxyConnection::compileRegex();
  475. #ifdef _WIN32
  476. WSADATA wsaData;
  477. if (WSAStartup(MAKEWORD(2, 0), &wsaData) == SOCKET_ERROR) {
  478. fprintf(stderr, "WSAStartup: error initializing WSA.\n");
  479. return -1;
  480. }
  481. #endif
  482. listener.addr_listener.sin_family = AF_INET;
  483. if(global) listener.addr_listener.sin_addr.s_addr = INADDR_ANY;
  484. else listener.addr_listener.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
  485. listener.addr_listener.sin_port = htons(listener.port);
  486. #ifdef _WIN32
  487. if ((listener.sock_listener = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == INVALID_SOCKET) {
  488. fprintf(stderr,"WSASocket: socket initialize error\n");
  489. return -1;
  490. }
  491. #else
  492. if (-1 == (listener.sock_listener = socket(AF_INET, SOCK_STREAM, 0))) {
  493. perror("socket");
  494. return -1;
  495. }
  496. #endif
  497. int optval=1;
  498. setsockopt(listener.sock_listener, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval));
  499. #ifdef _WIN32
  500. optval = SO_SYNCHRONOUS_NONALERT;
  501. setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&optval, sizeof(optval));
  502. #endif
  503. socklen_t addrlen = sizeof(listener.addr_listener);
  504. if (-1 == bind(listener.sock_listener, (struct sockaddr *)&listener.addr_listener, addrlen)) {
  505. perror("bind");
  506. return -1;
  507. }
  508. if (-1 == listen(listener.sock_listener, backlog)) {
  509. perror("listen");
  510. return -1;
  511. }
  512. if (-1 == getsockname(listener.sock_listener, (struct sockaddr *)&listener.addr_listener, &addrlen)) {
  513. perror("getsockname");
  514. return -1;
  515. }
  516. #ifndef _WIN32
  517. signal( SIGPIPE , SIG_IGN );
  518. #endif
  519. pthread_t thread_listener;
  520. if(0 != pthread_create(&thread_listener , NULL , listen , &listener))
  521. perror("pthread_create");
  522. pthread_join(thread_listener, NULL);
  523. return 0;
  524. }