💾 Archived View for gemini.rmf-dev.com › repo › Vaati › gmi_proxy › files › b319efe88ba0d5f5e183176e… captured on 2023-04-19 at 23:46:16. Gemini links have been rewritten to link to archived content

View Raw

More Information

➡️ Next capture (2023-09-08)

-=-=-=-=-=-=-

0 /* See LICENSE file for copyright and license details. */

1 #if defined(__OpenBSD__) || defined(__FreeBSD__)

2 #undef _POSIX_C_SOURCE

3 #include <sys/types.h>

4 #include <sys/sysctl.h>

5 #endif

6 #include <stdio.h>

7 #include <stdlib.h>

8 #include <unistd.h>

9 #include <string.h>

10 #include <errno.h>

11 #include <poll.h>

12 #include <pthread.h>

13 #include <signal.h>

14 #include <fcntl.h>

15 #include <tls.h>

16 #include <netinet/in.h>

17 #include <netdb.h>

18 #include <sys/socket.h>

19 #ifdef __linux__

20 #include <sys/sysinfo.h>

21 #endif

22 #include "strlcpy.h"

23 #include "strnstr.h"

24 #include "util.h"

25 #include "server.h"

26 #include "conf.h"

27 #include "log.h"

28 #include "cert.h"

29 #include "sandbox.h"

30

31 #define MAX_THREADS 4096

32

33 #ifndef PATH_MAX

34 #define PATH_MAX 2048

35 #endif

36

37 #define MAX_CLIENTS 512

38

39 #define TIMEOUT_LAST 9

40 #define TIMEOUT_START 2

41

42 #define ALTERNATE

43

44 enum {

45 STATE_NEW, /* initial state after getting accepted */

46 STATE_TLS, /* tls accept completed */

47 STATE_HANDSHAKED, /* tls handshake completed */

48 STATE_READING, /* reading server response */

49 STATE_DONE

50 };

51

52 struct thread {

53 struct pollfd fds[MAX_CLIENTS + 1];

54 struct client clients[MAX_CLIENTS];

55 unsigned int last;

56 int pair[2];

57 pthread_t thread;

58 pthread_mutex_t mutex;

59 };

60

61 struct proxy {

62 struct tls_config *config;

63 struct tls *ctx;

64 int socket;

65 int pair[2];

66 bool running;

67 struct thread* threads;

68 int nthreads;

69 pthread_t listener;

70 pthread_t watch;

71 int watch_pair[2];

72 } proxy = {0};

73

74 /* hide query because it could be a password */

75 void sanitize_url(const char *url, char *out, size_t len) {

76

77 const char *ptr = strrchr(url, '?') + 1;

78 size_t i = ptr - url + 1;

79

80 strlcpy(out, url, MAX(len, i));

81 if (i >= len) return;

82 strlcpy(&out[i - 1], "<*>", len - i);

83 }

84

85

86 void lock_thread(struct thread* thread) {

87 if (thread)

88 pthread_mutex_lock(&thread->mutex);

89 }

90

91 void unlock_thread(struct thread* thread) {

92 if (thread)

93 pthread_mutex_unlock(&thread->mutex);

94 }

95

96 void proxy_clean() {

97

98 int id, i;

99

100 if (!proxy.running) return;

101 proxy.running = 0;

102 log_info("Shutting down server");

103 id = -1;

104 for (i = 0; i < proxy.nthreads; i++) {

105 int result;

106 send(proxy.threads[i].pair[1], &id, sizeof(id), 0);

107 close(proxy.threads[i].pair[1]);

108 result = pthread_mutex_trylock(&proxy.threads[i].mutex);

109 if (result && result != EBUSY) exit(-1);

110 pthread_mutex_unlock(&proxy.threads[i].mutex);

111 pthread_mutex_destroy(&proxy.threads[i].mutex);

112 }

113 send(proxy.pair[1], &id, sizeof(id), 0);

114 close(proxy.watch_pair[0]);

115 close(proxy.watch_pair[1]);

116 close(proxy.pair[0]);

117 close(proxy.pair[1]);

118 if (proxy.config) {

119 tls_config_free(proxy.config);

120 proxy.config = NULL;

121 }

122 if (proxy.ctx) {

123 tls_close(proxy.ctx);

124 tls_free(proxy.ctx);

125 proxy.ctx = NULL;

126 }

127 }

128

129 int proxy_bind(int port) {

130

131 struct sockaddr_in addr;

132

133 proxy.socket = socket(AF_INET, SOCK_STREAM, 0);

134 if (proxy.socket == -1) {

135 log_error("Failed to open socket : %s", strerror(errno));

136 return -1;

137 }

138

139 addr.sin_family = AF_INET;

140 addr.sin_port = htons(port);

141 addr.sin_addr.s_addr = INADDR_ANY;

142 if (bind(proxy.socket, (struct sockaddr *) &addr, sizeof(addr))) {

143 log_error("Failed to bind socket : %s", strerror(errno));

144 return-1;

145 }

146

147 if (listen(proxy.socket, 5)) {

148 log_error("Failed to listen : %s", strerror(errno));

149 return -1;

150 }

151

152 return 0;

153 }

154

155 int proxy_accept(struct client *client);

156 int proxy_new(struct thread* thread, int fd) {

157

158 struct client* client = NULL;

159 unsigned int id = -1, i;

160

161 for (i = 0; i < SIZEOF(thread->clients); i++) {

162 if (thread->clients[i].addr_len != 0) continue;

163 client = &thread->clients[i];

164 id = i;

165 break;

166 }

167 if (!client) return -1;

168 PZERO(client);

169 client->addr_len = sizeof(client->addr);

170 client->server_sock = -1;

171 client->sock = accept(fd, (struct sockaddr*)&client->addr,

172 &client->addr_len);

173 if (client->sock == -1) {

174 PZERO(client);

175 sleep(1); /* sleep in case of a shortage of file descriptors */

176 return -1;

177 }

178

179 client->state = STATE_NEW;

180 client->id = id + 1;

181 client->tid = thread - proxy.threads;

182 client->thread = thread;

183 client->last = client->start = time(NULL);

184 thread->fds[id + 1].events = POLLIN;

185 thread->fds[id + 1].fd = client->sock;

186

187 if (thread->last < id + 1)

188 thread->last = id + 1;

189 send(thread->pair[1], &client->id, sizeof(client->id), 0);

190 proxy_accept(client);

191 return 0;

192 }

193

194 int proxy_accept(struct client *client) {

195

196 if (tls_accept_socket(proxy.ctx, &client->ctx, client->sock)) {

197 return -1;

198 }

199

200 #ifdef DEBUG

201 log_debug("Incoming connection [%d, %d]", client->tid, client->id);

202 #endif

203 client->state = STATE_TLS;

204 return 0;

205 }

206

207 void* proxy_listen() {

208

209 struct pollfd fds[2];

210 int i, ready;

211

212 if (socketpair(AF_UNIX, SOCK_STREAM, 0, proxy.pair)) {

213 log_error("Initialization failure, socketpair: %s",

214 strerror(errno));

215 return NULL;

216 }

217

218 fds[0].events = POLLIN;

219 fds[0].fd = proxy.pair[0];

220 fds[1].events = POLLIN;

221 fds[1].fd = proxy.socket;

222 i = 0;

223 while (proxy.running) {

224 ready = poll(fds, 2, -1);

225 if (!proxy.running) break;

226 if (ready == -1) {

227 log_error("poll error: %s", strerror(errno));

228 proxy_clean();

229 break;

230 }

231 if (fds[0].revents & POLLIN) {

232 recv(fds[0].fd, &i, sizeof(i), 0);

233 if (!proxy.running) break;

234 ready--;

235 if (!ready) continue;

236 }

237 #ifdef DEBUG

238 log_debug("accepting new connection on thread %d (%d)",

239 i, ready);

240 #endif

241 if (fds[1].revents & POLLIN) {

242 proxy_new(&proxy.threads[i], proxy.socket);

243 }

244 i = (i + 1) % proxy.nthreads;

245 }

246 return NULL;

247 }

248

249 void proxy_close(struct client *client) {

250 client->thread->fds[client->id].fd = -1;

251 client->thread->fds[client->id].events = POLLIN;

252 #ifdef DEBUG

253 log_debug_r(client, "Closing connection [%d, %d]",

254 client->tid, client->id);

255 #endif

256 if (client->conn) {

257 tls_close(client->conn);

258 tls_free(client->conn);

259 }

260 if (client->server_sock > 0)

261 close(client->server_sock);

262 if (client->conn_config) {

263 tls_config_free(client->conn_config);

264 }

265 if (client->ctx) {

266 tls_close(client->ctx);

267 tls_free(client->ctx);

268 }

269 if (client->sock > 0)

270 close(client->sock);

271 PZERO(client);

272 }

273

274 void* proxy_watch() {

275 int code, i;

276 struct pollfd pfd;

277 socketpair(AF_UNIX, SOCK_STREAM, 0, proxy.watch_pair);

278 pfd.revents = POLLIN;

279 pfd.fd = proxy.watch_pair[1];

280 start:

281 if (poll(&pfd, 1, 2000) > 0)

282 recv(proxy.watch_pair[1], &code, sizeof(code), 0);

283 if (!proxy.running) return NULL;

284 for (i = 0; i < proxy.nthreads; i++) {

285 time_t now = time(NULL);

286 size_t j;

287 for (j = 0; j < SIZEOF(proxy.threads[i].clients); j++) {

288 struct client *client = &proxy.threads[i].clients[j];

289 if (proxy.threads[i].fds[j + 1].fd == -1) continue;

290 if ((!client->handshaked &&

291 client->last + TIMEOUT_START < now) ||

292 (client->last + TIMEOUT_LAST < now)) {

293 #ifdef DEBUG

294 log_debug_r(&proxy.threads[i].clients[j],

295 "Closing hanged connection");

296 #endif

297 lock_thread(&proxy.threads[i]);

298 proxy_close(&proxy.threads[i].clients[j]);

299 unlock_thread(&proxy.threads[i]);

300 send(proxy.threads[i].pair[1], &i,

301 sizeof(i), 0);

302 }

303 }

304 }

305 goto start;

306 }

307

308 int proxy_connect(struct client *client, const char *host, const char *port) {

309

310 int sock, addr_size, connected, failed;

311 int family = AF_INET;

312 struct addrinfo hints = {0}, *result;

313 struct sockaddr_in addr4 = {0};

314 struct sockaddr_in6 addr6 = {0};

315

316 sock = socket(family, SOCK_STREAM, 0);

317 if (sock == -1) {

318 log_error_r(client, "Failed to create socket: %s",

319 strerror(errno));

320 return -1;

321 }

322

323 hints.ai_family = AF_INET;

324 hints.ai_socktype = SOCK_STREAM;

325 hints.ai_flags |= AI_CANONNAME;

326 errno = 0;

327

328 if ((getaddrinfo(host, NULL, &hints, &result))) {

329 log_error_r(client, "Unknown domain name: %s, %s",

330 host, strerror(errno));

331 close(sock);

332 return -1;

333 }

334

335 if (result->ai_family == AF_INET) {

336 addr4.sin_addr =

337 ((struct sockaddr_in*)result->ai_addr)->sin_addr;

338 addr4.sin_family = AF_INET;

339 addr4.sin_port = htons(atoi(port));

340 } else if (result->ai_family == AF_INET6) {

341 addr6.sin6_addr =

342 ((struct sockaddr_in6*)result->ai_addr)->sin6_addr;

343 addr6.sin6_family = AF_INET6;

344 addr6.sin6_port = htons(atoi(port));

345 } else {

346 log_error_r(client,

347 "Unexpected error, invalid address family %s", host);

348 close(sock);

349 return -1;

350 }

351

352 family = result->ai_family;

353 addr_size = (family == AF_INET) ? sizeof(struct sockaddr_in) :

354 sizeof(struct sockaddr_in6);

355

356 failed = connect(sock, (family == AF_INET) ?

357 (struct sockaddr*)&addr4 :

358 (struct sockaddr*)&addr6, addr_size);

359 failed = failed ? (errno != EAGAIN && errno != EWOULDBLOCK &&

360 errno != EINPROGRESS && errno != EALREADY &&

361 errno != 0) : failed;

362 connected = 0;

363 while (!failed) {

364

365 struct pollfd fds[2];

366 int count, value, ret;

367 socklen_t len;

368

369 fds[0].fd = sock;

370 fds[0].events = POLLOUT;

371 count = poll(fds, 1, 2 * 1000);

372 if (count < 1 || fds[0].revents != POLLOUT)

373 break;

374

375 len = sizeof(value);

376 ret = getsockopt(sock, SOL_SOCKET, SO_ERROR, &value, &len);

377 connected = (value == 0 && ret == 0);

378 break;

379 }

380

381 freeaddrinfo(result);

382

383 if (!connected) {

384 log_error_r(client, "Connection to %s:%s timed out : %s",

385 host, port, strerror(errno));

386 close(sock);

387 return -1;

388 }

389

390 if (tls_connect_socket(client->conn, sock, host)) {

391 log_error_r(client, "Unable to connect to: %s:%s : %s",

392 host, port,

393 ERRNO_IF_NULL(tls_error(client->ctx)));

394 close(sock);

395 return -1;

396 }

397

398 if (tls_handshake(client->conn)) {

399 log_error_r(client, "Handshake failed with %s:%s : %s",

400 host, port,

401 ERRNO_IF_NULL(tls_error(client->ctx)));

402 close(sock);

403 return -1;

404 }

405

406 client->server_sock = sock;

407

408 return 0;

409 }

410

411 int proxy_create_cert(struct client *client) {

412

413 char crt[PATH_MAX];

414 char key[PATH_MAX];

415 const char* path;

416 const char* hash;

417 int fd;

418

419 hash = tls_peer_cert_hash(client->ctx);

420 if (!hash) return 0;

421 hash += 7; /* the hash start with 'SHA256:' */

422 path = conf.clients;

423 snprintf(crt, sizeof(crt), "%s/%s.crt", path, hash);

424 snprintf(key, sizeof(key), "%s/%s.key", path, hash);

425 fd = open(crt, O_RDONLY);

426 if (fd < 0 && cert_create(crt, key) < 0) {

427 if (fd > -1) close(fd);

428 log_error_r(client, "Failed to create client certificate");

429 return 0;

430 } else {

431 close(fd);

432 }

433 tls_config_set_keypair_file(client->conn_config, crt, key);

434 return 1;

435 }

436

437 int proxy_handshake(struct client *client) {

438

439 const char *servername;

440 int len;

441

442 if (tls_handshake(client->ctx)) return -1;

443

444 servername = tls_conn_servername(client->ctx);

445 if (!servername) {

446 log_error_r(client, "Failed to fetch server name");

447 return STRCPY(client->request, "53 Unknown domain\r\n");

448 }

449

450 client->server = conf_get(servername);

451 if (!client->server) {

452 log_error_r(client, "No virtual server for %s",

453 servername);

454 return STRCPY(client->request, "53 Invalid domain\r\n");

455 }

456

457 client->conn_config = tls_config_new();

458 if (!client->conn_config) {

459 log_error_r(client, "tls_config_new: %s", strerror(errno));

460 return STRCPY(client->request, "53 Bad gateway\r\n");

461 }

462 tls_config_insecure_noverifycert(client->conn_config);

463

464 client->conn = tls_client();

465 if (!client->conn) {

466 log_error_r(client, "tls_client: %s", strerror(errno));

467 return STRCPY(client->request, "53 Bad gateway\r\n");

468 }

469

470 if (client->server->client)

471 proxy_create_cert(client);

472

473 tls_configure(client->conn, client->conn_config);

474

475 len = proxy_connect(client, client->server->relayto,

476 client->server->relayto_port);

477 if (len < 0)

478 return STRCPY(client->request, "53 Bad gateway\r\n");

479

480 client->handshaked = 1;

481 client->state = STATE_HANDSHAKED;

482 #ifdef DEBUG

483 log_debug_r(client, "handshake completed");

484 #endif

485

486 return 0;

487 }

488

489 int proxy_read_request(struct client *client) {

490

491 int i;

492 char *ptr, hostname[1024], buf[1024], url[1024];

493

494 i = TLS_WANT_POLLIN;

495 i = tls_read(client->ctx, &client->request[client->len],

496 sizeof(client->request) - client->len);

497 if (i == TLS_WANT_POLLIN) return 0;

498 if (i <= 0) {

499 log_error_r(client, "Failed to read server data, %s",

500 tls_error(client->ctx));

501 return -1;

502 }

503 client->len += i;

504 if (client->request[client->len - 2] != '\r' ||

505 client->request[client->len - 1] != '\n') {

506 if (client->len < sizeof(client->request))

507 return 0;

508 log_error_r(client, "Client sent invalid request");

509 return -1;

510 }

511

512 ptr = strnstr(client->request, "gemini://", sizeof(client->request));

513 if (!ptr) {

514 log_error_r(client, "Client sent invalid request");

515 return STRCPY(client->request, "59 Request too long\r\n");

516 }

517 ptr += sizeof("gemini://") - 1;

518 client->request[client->len - 2] = '\0';

519 STRCPY(buf, ptr);

520 client->request[client->len - 2] = '\r';

521 ptr = strchr(buf, '/');

522 strlcpy(hostname, buf, ptr ?

523 (unsigned)(ptr - buf + 1) : sizeof(hostname));

524 if (strncmp(hostname, client->server->name, sizeof(hostname))) {

525 log_error_r(client, "Client requested invalid server name");

526 return STRCPY(client->request, "59 Wrong server name\r\n");

527 }

528 if (ptr) STRCPY(client->url, ptr);

529 else STRCPY(client->url, "/");

530

531 sanitize_url(client->url, url, sizeof(url));

532 log_info_r(client, "%s%s", client->server->relayto, url);

533

534 i = snprintf(buf, sizeof(buf), "gemini://%s%s\r\n",

535 client->server->relayto, client->url);

536 if (tls_write(client->conn, buf, i) != i) {

537 log_error_r(client, ERRNO_IF_NULL(tls_error(client->conn)));

538 return STRCPY(client->request, "53 Invalid response\r\n");

539 }

540

541 client->thread->fds[client->id].fd = client->server_sock;

542 client->state = STATE_READING;

543 #ifdef DEBUG

544 log_debug_r(client, "request sent");

545 #endif

546

547 return 0;

548 }

549

550 int proxy_read_server(struct client *client) {

551

552 int len;

553 char buf[1024];

554

555 len = tls_read(client->conn, buf, sizeof(buf));

556 if (!len) {

557 client->thread->fds[client->id].fd = client->sock;

558 client->thread->fds[client->id].events = POLLOUT;

559 #ifdef DEBUG

560 log_debug_r(client, "transfer completed");

561 #endif

562 client->state = STATE_DONE;

563 return 0;

564 }

565 if (len == TLS_WANT_POLLIN) return 0;

566 if (len > 0) {

567 if (tls_write(client->ctx, buf, len) != len)

568 return -1;

569 #ifdef ALTERNATE

570 client->thread->fds[client->id].events = POLLOUT;

571 client->thread->fds[client->id].fd = client->sock;

572 #endif

573 return 0;

574 }

575 log_error_r(client, ERRNO_IF_NULL(tls_error(client->conn)));

576 return STRCPY(client->request, "53 Invalid response\r\n");

577 }

578

579 int proxy_read(struct client *client) {

580

581 int len;

582

583 lock_thread(client->thread);

584 client->last = time(NULL);

585 len = 0;

586 switch (client->state) {

587 case STATE_NEW:

588 len = proxy_accept(client);

589 break;

590 case STATE_TLS:

591 len = proxy_handshake(client);

592 break;

593 case STATE_HANDSHAKED:

594 len = proxy_read_request(client);

595 break;

596 case STATE_READING:

597 len = proxy_read_server(client);

598 break;

599 }

600 if (len > 0) {

601 tls_write(client->ctx, client->request, len);

602 client->last = time(NULL);

603 client->thread->fds[client->id].events = POLLOUT;

604 }

605 unlock_thread(client->thread);

606 return -!!len;

607 }

608

609 void* proxy_thread(void *ptr) {

610 struct thread *thread = ptr;

611 while (proxy.running) {

612 unsigned int nfds = SIZEOF(thread->fds), i;

613 /* 1 + thread->last */

614 int ready = poll(thread->fds, nfds - 1, -1);

615 if (!proxy.running) break;

616 if (ready == -1) {

617 log_error("poll error: %s", strerror(errno));

618 proxy_clean();

619 break;

620 }

621 if (thread->fds[0].revents == POLLIN) {

622 char b;

623 recv(thread->fds[0].fd, &b, sizeof(b), 0);

624 ready--;

625 if (!proxy.running) break;

626 }

627 for (i = 1; i < nfds && ready > 0; i++) {

628 int id = i - 1;

629 if (thread->fds[i].fd == -1) continue;

630 ready--;

631 if (thread->fds[i].revents & POLLOUT) {

632 #ifdef ALTERNATE

633 if (thread->clients[id].state != STATE_DONE) {

634 thread->fds[i].events = POLLIN;

635 thread->fds[i].fd =

636 thread->clients[id].

637 server_sock;

638 continue;

639 }

640 #endif

641 proxy_close(&thread->clients[id]);

642 continue;

643 }

644 if (thread->fds[i].revents & POLLIN ||

645 thread->fds[i].revents & POLLRDNORM ||

646 thread->fds[i].revents & POLLRDBAND ) {

647 if (!proxy_read(&thread->clients[id]))

648 continue;

649 log_error_r(&thread->clients[id],

650 "Failed to read data from client");

651 }

652 proxy_close(&thread->clients[id]);

653 }

654 }

655 return NULL;

656 }

657

658 int proxy_init_thread() {

659

660 int i;

661 unsigned int j;

662

663 #if defined(__OpenBSD__) || defined(__FreeBSD__)

664 proxy.nthreads = 0;

665 if (conf.threads) {

666 proxy.nthreads = conf.threads;

667 } else {

668 int mib[2], maxproc;

669 size_t len;

670

671 mib[0] = CTL_KERN;

672 mib[1] = KERN_MAXPROC;

673 len = sizeof(maxproc);

674 if (!sysctl(mib, 2, &maxproc, &len, NULL, 0)) {

675 proxy.nthreads = maxproc;

676 }

677 }

678 #else

679 proxy.nthreads = conf.threads ? conf.threads : get_nprocs();

680 #endif

681 if (proxy.nthreads < 1) proxy.nthreads = 1;

682 if (proxy.nthreads > MAX_THREADS) proxy.nthreads = MAX_THREADS;

683 proxy.threads = malloc(sizeof(struct thread) * proxy.nthreads);

684 if (!proxy.threads) {

685 log_error("Memory allocation failure");

686 return -1;

687 }

688 memset(proxy.threads, 0, sizeof(struct thread) * proxy.nthreads);

689 for (i = 0; i < proxy.nthreads; i++) {

690 if (socketpair(AF_UNIX, SOCK_STREAM, 0, proxy.threads[i].pair))

691 return -1;

692 for (j = 0; j < SIZEOF(proxy.threads[i].fds); j++)

693 proxy.threads[i].fds[j].fd = -1;

694

695 proxy.threads[i].fds[0].fd = proxy.threads[i].pair[0];

696 proxy.threads[i].fds[0].events = POLLIN;

697 pthread_mutex_init(&proxy.threads[i].mutex, NULL);

698 pthread_create(&proxy.threads[i].thread, NULL,

699 proxy_thread, &proxy.threads[i]);

700 }

701 pthread_create(&proxy.listener, NULL, proxy_listen, NULL);

702 pthread_create(&proxy.watch, NULL, proxy_watch, NULL);

703 return 0;

704 }

705

706 void proxy_handler(int sig) {

707 if (!sig) return;

708 proxy_clean();

709 }

710

711 int proxy_init(int port) {

712

713 struct server *server;

714 int started;

715

716 signal(SIGPIPE, SIG_IGN);

717

718 if (tls_init()) {

719 log_error("tls_init: %s", strerror(errno));

720 return -1;

721 }

722

723 proxy.config = tls_config_new();

724 if (!proxy.config) {

725 log_error("tls_config_new: %s", strerror(errno));

726 return -1;

727 }

728 tls_config_verify_client_optional(proxy.config);

729

730

731 proxy.ctx = tls_server();

732 if (!proxy.ctx) {

733 log_error("tls_server: %s", strerror(errno));

734 return -1;

735 }

736

737 started = 0;

738 for (server = servers; server->exist != END_OF_ARRAY; server++) {

739 int ret;

740 if (!server->exist) continue;

741 ret = started ?

742 tls_config_add_keypair_file(proxy.config,

743 server->certificate, server->key) :

744 tls_config_set_keypair_file(proxy.config,

745 server->certificate, server->key);

746 started = 1;

747 if (ret) {

748 const char *error = tls_config_error(proxy.config);

749 log_error("%s", ERRNO_IF_NULL(error));

750 return -1;

751 }

752 }

753

754 if (sandbox()) {

755 log_error("Sandboxing failure: %s", strerror(errno));

756 return -1;

757 }

758

759 tls_config_insecure_noverifycert(proxy.config);

760

761 if (tls_configure(proxy.ctx, proxy.config)) {

762 const char *error = tls_error(proxy.ctx);

763 log_error("tls_configure: %s", ERRNO_IF_NULL(error));

764 return -1;

765 }

766

767 if (proxy_bind(port)) {

768 return -1;

769 }

770

771 proxy.running = 1;

772 if (proxy_init_thread()) {

773 return -1;

774 }

775 log_info("Server listening on port %d", port);

776 log_info("%d thread%s created", proxy.nthreads,

777 proxy.nthreads > 1 ? "s" : "");

778

779 signal(SIGINT, proxy_handler);

780

781 return 0;

782 }

783

784 void proxy_join() {

785 int i;

786 if (!proxy.threads) return;

787 for (i = 0; i < proxy.nthreads; i++) {

788 pthread_join(proxy.threads[i].thread, NULL);

789 }

790 pthread_join(proxy.listener, NULL);

791 pthread_join(proxy.watch, NULL);

792 free(proxy.threads);

793 log_info("Server stopped");

794 }

795