💾 Archived View for gmi.noulin.net › gitRepositories › tuyau › file › sserver.c.gmi captured on 2023-07-10 at 18:14:20. Gemini links have been rewritten to link to archived content
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
sserver.c (22827B)
1 #! /usr/bin/env sheepy 2 /* or direct path to sheepy: #! /usr/local/bin/sheepy */ 3 4 /* Libsheepy documentation: https://spartatek.se/libsheepy/ */ 5 #include <netdb.h> // for gethostbyname 6 #include <netinet/in.h> 7 #include <string.h> 8 #include <stdlib.h> 9 #include <unistd.h> 10 11 // open 12 #include <sys/types.h> 13 #include <sys/stat.h> 14 #include <fcntl.h> 15 16 #include <glob.h> 17 18 #include <openssl/err.h> 19 //#include <openssl/pem.h> 20 #include <openssl/ssl.h> 21 //#include <openssl/x509v3.h> 22 23 // inet_ntoa 24 #include <sys/socket.h> 25 #include <netinet/in.h> 26 #include <arpa/inet.h> 27 28 // basename 29 #include <libgen.h> 30 31 // statvfs 32 #include <sys/statvfs.h> 33 34 #include "libsheepyObject.h" 35 #include "netFrame.h" 36 #include "shpPackages/short/short.h" 37 #include "makeHeader.h" 38 39 #include "rateLimiter/rateLimiter.h" 40 41 #define CONFIG "~/.tuyau/serverConfig.yml" 42 43 int packetCount = 0; 44 // file description for writing received chunks of big files 45 int fd = -1; 46 u64 transferSz = 0; 47 // client socket 48 int mysock = 0; 49 SSL *ssl; 50 rateLimitert *rateLim = null; 51 u32 clientIp = 0; 52 53 smallJsont *tokens = null; 54 smallJsont *relays = null; 55 56 // relay variables 57 SSL_CTX *relay_ssl_ctx = null; 58 SSL *relay_ssl = null; 59 int relay_sock = -1; 60 netFramet *relay_netframe = null; 61 // when the client sends files to the destination 62 // and the client closes the connection to this relay server, 63 // close the connection to the destination normaly. 64 // when the destination closes the connection only cleanup of the destination 65 // connection is needed 66 // This is needed because when the client closes the connection, the receive loop 67 // breaks. 68 bool closeDestConnection = no; 69 70 /* enable/disable logging */ 71 /* #undef pLog */ 72 /* #define pLog(...) */ 73 74 void closeRelayConnectionToDest(void); 75 void saveReceivedData(void *receiveB, size_t sz); 76 bool relayForwardDataToClient(void *receiveB, size_t sz, void *context); 77 78 // TODO return error from netframe callback 79 80 bool cb(void *buf, size_t size, void *context) { 81 saveReceivedData(buf, size); 82 ret yes; 83 } 84 85 void loadCertificates(SSL_CTX* ctx, char* certFilename, char* keyFilename) 86 { 87 // set the local certificate 88 if (SSL_CTX_use_certificate_file(ctx, certFilename, SSL_FILETYPE_PEM) <= 0) { 89 logC("Error loadind cert file %s", certFilename); 90 XFailure; 91 } 92 // set the private key 93 if (SSL_CTX_use_PrivateKey_file(ctx, keyFilename, SSL_FILETYPE_PEM) <= 0) { 94 logC("Error loadind key file %s", keyFilename); 95 XFailure; 96 } 97 /* verify private key */ 98 if (!SSL_CTX_check_private_key(ctx)) { 99 logC("Private key does not match the public certificate", keyFilename); 100 XFailure; 101 } 102 } 103 104 int main(int ARGC, char** ARGV) { 105 106 initLibsheepy(ARGV[0]); 107 setLogMode(LOG_FUNC); 108 109 // block ips for 10mn when token is wrong 110 initiateAllocateRateLimiter(&rateLim); 111 setupG(rateLim, 1000000 /* max clients */, 600 /* window 10mn */, 0 /* max access count */); 112 113 SSL_CTX *ctx; 114 ctx = SSL_CTX_new(TLS_server_method()); 115 int r = SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION); 116 if (!SSL_CTX_set_min_proto_version(ctx, TLS1_3_VERSION)) { 117 logE("Can't force minimum TLS 1.3"); 118 ret 1; 119 } 120 if (!SSL_CTX_set_cipher_list(ctx, 121 "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:" 122 "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:" 123 "ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:" 124 "DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:" 125 "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:" 126 "TLS_CHACHA20_POLY1305_SHA256")) { 127 logE("Can't set cipher list"); 128 ret 1; 129 } 130 131 SSL_CTX_set_options(ctx, SSL_OP_NO_RENEGOTIATION); 132 133 loadCertificates(ctx, "cert.pem", "key.pem"); 134 135 136 // Steps 137 // load configuration 138 // create tokens dict 139 // open listen socket 140 // start event loop 141 142 char *c = ARGV[1] ? ARGV[1] : CONFIG; 143 144 // load configuration 145 cleanCharP(config) = expandHome(c); 146 cleanAllocateSmallJson(cfg); 147 readFileG(cfg, config); 148 149 lv(cfg); 150 151 if (isEmptyG(cfg)) { 152 logC("Empty configuration %s", c); 153 ret 1; 154 } 155 156 tokens = allocG(rtSmallJsont); 157 relays = allocG(rtSmallJsont); 158 159 iter(cfg, D) { 160 if (!isOSmallDictG(D)) continue; 161 cast(smallDictt*,d,D); 162 if (hasG(d, "root")) { 163 // local home 164 setG(tokens, $(d,"token"), $(d,"root")); 165 } 166 elif (hasG(d, "hostname")) { 167 // relay 168 setG(relays, $(d,"token"), d); 169 } 170 } 171 172 lv(tokens); 173 lv(relays); 174 175 // open listen socket 176 int sock; 177 struct sockaddr_in server; 178 int rval; 179 180 sock = socket(AF_INET, SOCK_STREAM, 0); 181 if (sock < 0){ 182 perror("Failed to create socket"); 183 XFailure; 184 } 185 186 u16 port = hasG(cfg, "port") ? u$(cfg, "port") : 1032; 187 lv(port); 188 server.sin_family = AF_INET; 189 server.sin_addr.s_addr = INADDR_ANY; 190 server.sin_port = htons(port); 191 192 if (bind(sock, (struct sockaddr *) &server, sizeof(server))){ 193 perror("bind failed"); 194 XFailure; 195 } 196 197 cleanAllocateNetFrame(netframe); 198 199 o(netframe, setCallback, cb, NULL /*context*/); 200 201 // start event loop 202 listen(sock, 5); 203 forever { 204 struct sockaddr_in addr; 205 socklen_t len = sizeof(addr); 206 mysock = accept(sock, (struct sockaddr *)&addr, &len); 207 if (mysock == -1) 208 perror("accept failed"); 209 else { 210 logI("Connection: %s:%d",inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); 211 clientIp = addr.sin_addr.s_addr; 212 if (o(rateLim,has, clientIp)) { 213 logI("Ip %s is blocked.", inet_ntoa(addr.sin_addr)); 214 close(mysock); 215 continue; 216 } 217 // get new SSL state with context 218 ssl = SSL_new(ctx); 219 // set connection socket to SSL state 220 SSL_set_fd(ssl, mysock); 221 // do SSL-protocol accept 222 if (SSL_accept(ssl) == -1) { 223 logE("Accept SSL connection"); 224 } 225 else { 226 var r = o(netframe,receive, ssl); 227 logVarG(r); 228 if (closeDestConnection) { 229 // close client connection 230 o(netframe,end, relay_ssl); 231 } 232 } 233 // release SSL state 234 SSL_free(ssl); 235 close(mysock); 236 if (relay_sock != -1) { 237 if (closeDestConnection) { 238 // some data needs to be received in order to send all data to the server, SSL_write says all the data is sent but it is not true, why? 239 // 478 bytes are received. It seems to be encrypted. 240 // SSL_shutdown() and shutdown() don't help 241 u8 buf[1024*1024] = init0Var; 242 int r = recv(relay_sock, buf, sizeof(buf), 0); 243 if (r == -1) { 244 logE("recv before closing the socket"); 245 } 246 } 247 closeRelayConnectionToDest(); 248 } 249 } 250 } 251 252 SSL_CTX_free(ctx); 253 terminateG(relays); 254 terminateG(tokens); 255 terminateO(rateLim); 256 } 257 258 // connect to destination, this server is a relay 259 bool connectToDest(smallDictt *svrInfo) { 260 261 relay_sock = socket(AF_INET, SOCK_STREAM, 0); 262 if (relay_sock < 0){ 263 perror("Failed to create socket"); 264 ret no; 265 } 266 267 struct sockaddr_in server; 268 struct hostent *hp; 269 270 server.sin_family = AF_INET; 271 272 hp = gethostbyname($(svrInfo, "hostname")); 273 if (hp==0) { 274 perror("gethostbyname failed"); 275 close(relay_sock); 276 relay_sock = -1; 277 ret no; 278 } 279 280 memcpy(&server.sin_addr, hp->h_addr, hp->h_length); 281 server.sin_port = htons(u$(svrInfo, "port")); 282 283 if (connect(relay_sock,(struct sockaddr *) &server, sizeof(server))){ 284 perror("connect failed"); 285 close(relay_sock); 286 relay_sock = -1; 287 ret no; 288 } 289 290 relay_ssl_ctx = SSL_CTX_new(TLS_method()); 291 BIO *sbio = BIO_new(BIO_f_ssl()); 292 relay_ssl = SSL_new(relay_ssl_ctx); 293 // attach the socket descriptor 294 SSL_set_fd(relay_ssl, relay_sock); 295 296 // perform the connection 297 if (SSL_connect(relay_ssl) == -1) { 298 logE("Couldn't establish the TLS connection"); 299 // clean state 300 closeRelayConnectionToDest(); 301 ret no; 302 } 303 304 ret yes; 305 } 306 307 void closeRelayConnectionToDest(void) { 308 // release SSL state 309 SSL_free(relay_ssl); 310 SSL_CTX_free(relay_ssl_ctx); 311 // TODO add recv to send all data? 312 close(relay_sock); 313 // clear relay state 314 relay_ssl = null; 315 relay_ssl_ctx = null; 316 relay_sock = -1; 317 terminateG(relay_netframe); 318 } 319 320 void saveReceivedData(void *receiveB, size_t sz) { 321 logVarG(sz); 322 323 if (relay_sock != -1) { 324 // this server is a relay and the connection to the destination 325 // is already established 326 // forward data from client to destination 327 o(relay_netframe,send , relay_ssl, receiveB, sz); 328 ret; 329 } 330 331 if (packetCount == 0) { 332 // check packet size 333 if (sz < (1/*command*/ + 8/*token*/)) ret; 334 // receive a new command 335 // header 336 u8 *command = (u8*) receiveB; 337 u8 *token = (u8*) (receiveB + 1); 338 char tk[9] = init0Var; 339 memcpy(tk, token, 8); 340 341 cleanFinishSmallDictP(svrInfo) = null; 342 343 if (not hasG(tokens, tk)) { 344 if (hasG(relays, tk)) { 345 // relay packets to destination 346 svrInfo = getG(relays, rtSmallDictt, tk); 347 logD("Relay to"); 348 lv(svrInfo); 349 } 350 else { 351 // invalid connection, block ip 352 incomingG(rateLim, clientIp); 353 logE("token not found"); 354 ret; 355 } 356 } 357 358 char *root = $(tokens, tk); 359 360 if (*command == 0) { 361 // receive file 362 363 if (svrInfo) { 364 // this server is a relay, connect to destination 365 if (not connectToDest(svrInfo)) { 366 logE("Relay: Can't connect to destination %m", svrInfo); 367 ret; 368 } 369 relay_netframe = allocNetFrame(); 370 // forward data from client to destination 371 closeDestConnection = yes; 372 o(relay_netframe,send , relay_ssl, receiveB, sz); 373 ret; 374 } 375 376 // check packet size 377 if (sz < (1/*command*/ + 8/*token*/ + 2 /*filenameLength*/ + 1 /*filename*/)) ret; 378 u16 *filenameLength = (u16*)(receiveB + 9); 379 if (*filenameLength > 4096) ret; 380 // check that filenameLength is correct 381 if (sz < (1/*command*/ + 8/*token*/ + 2 /*filenameLength*/ + *filenameLength /*filename*/)) ret; 382 // receiveB + 11 = filename 383 cleanCharP(filename) = malloc(*filenameLength + 1); 384 filename[*filenameLength] = 0; 385 memcpy(filename, receiveB + 11, *filenameLength); 386 u32 bufi = 11 + *filenameLength; 387 // check that filemode and path are in the buffer 388 if (sz < (bufi + 2 /*filemode*/ + 2 /*pathLength*/)) ret; 389 u16 *filemode = (u16*)(receiveB + bufi); 390 bufi += 2; 391 u16 *pathLength = (u16*)(receiveB + bufi); 392 if (*pathLength > 4096) ret; 393 bufi += 2; 394 // check path length is correct and that filesize is in the buffer 395 if (sz < (bufi + *pathLength + 8 /*filesize*/)) ret; 396 cleanCharP(destPath) = null; 397 if (*pathLength) { 398 destPath = malloc(*pathLength + 1); 399 memcpy(destPath, receiveB + bufi, *pathLength); 400 destPath[*pathLength] = 0; 401 bufi += *pathLength; 402 } 403 // file size 404 u64 *filesize = (u64*)(receiveB + bufi); 405 bufi += 8; 406 407 logD("bufi %d fsz %d + %d, filename %s, destPath %s",bufi, *filesize, bufi + *filesize, filename, destPath); 408 409 // local filename 410 char *path = catS(root, "/", nS(destPath)); 411 pErrorNULL(normalizePathG(&path)); 412 pErrorNULL(trimG(&path)); 413 cleanCharP(nroot) = normalizePathG(root); 414 //lv(path); 415 // make sure path is inside root 416 if (not startsWithG(path, nroot)) { 417 logE("Incorrect path"); 418 ret; 419 } 420 421 // check isdir or if there is a filename 422 bool filenameInDestPath = no; 423 if (destPath and not isPath(path)) { 424 if (endsWithG(destPath,'/')) { 425 logE("Directory doesn't exist %s", path); 426 ret; 427 } 428 cleanCharP(dir) = shDirname(path); 429 if (not isPath(dir)) { 430 logE("Directory doesn't exist %s", dir); 431 ret; 432 } 433 filenameInDestPath = yes; 434 // check if there is enough free space on disk 435 struct statvfs fs; 436 if (statvfs(dir, &fs) == -1) { 437 shperror("statvfs check free space"); 438 ret; 439 } 440 if (*filesize >= fs.f_bsize * fs.f_bavail) { 441 logE("Not enough free space available in path %s", path); 442 } 443 } 444 //lv(filenameInDestPath); 445 if (not filenameInDestPath) { 446 // check if there is enough free space on disk 447 struct statvfs fs; 448 if (statvfs(path, &fs) == -1) { 449 shperror("statvfs check free space"); 450 ret; 451 } 452 if (*filesize >= fs.f_bsize * fs.f_bavail) { 453 logE("Not enough free space available in path %s", path); 454 } 455 pErrorNULL(iAppendManyS(&path, "/", filename)); 456 } 457 lv(path); 458 459 if (*filesize <= sz - bufi) { 460 // the file is smaller than the network buffer, the complete file is already here 461 pError0(writeFile(path, receiveB + bufi, *filesize)); 462 pError0(fileChmod(path, *filemode)); 463 } 464 else { 465 logD("open fd"); 466 // increase packetCount to receive big file in chunks 467 inc packetCount; 468 fd = open(path, O_WRONLY | O_CREAT, *filemode); 469 if (fd == -1) { 470 logE("cant open %s", path); 471 ret; 472 } 473 int r = write(fd, receiveB + bufi, sz - bufi); 474 if (r == -1) { 475 logE("cant write %s", path); 476 ret; 477 } 478 transferSz = *filesize - (sz - bufi); 479 } 480 } 481 elif (*command == 1) { 482 // mkdir 483 484 if (svrInfo) { 485 // this server is a relay, connect to destination 486 if (not connectToDest(svrInfo)) { 487 logE("Relay: Can't connect to destination %m", svrInfo); 488 ret; 489 } 490 relay_netframe = allocNetFrame(); 491 // forward data from client to destination 492 closeDestConnection = yes; 493 o(relay_netframe,send , relay_ssl, receiveB, sz); 494 ret; 495 } 496 497 // check packet size 498 if (sz < (1/*command*/ + 8/*token*/ + 2 /*filemode*/ + 2 /*pathLength*/ + 1 /*path*/)) ret; 499 u16 *filemode = (u16*)(receiveB + 9); 500 u16 *pathLength = (u16*)(receiveB + 11); 501 if (*pathLength > 4096) ret; 502 // check that pathLength is correct, path has to be at least 1 byte 503 if (sz < (1/*command*/ + 8/*token*/ + 2 /*filemode*/ + 2 /*pathLength*/ + *pathLength /*path*/)) ret; 504 cleanCharP(destPath) = malloc(*pathLength + 1); 505 memcpy(destPath, receiveB + 13, *pathLength); 506 destPath[*pathLength] = 0; 507 cleanCharP(path) = catS(root, "/", destPath); 508 pErrorNULL(normalizePathG(&path)); 509 pErrorNULL(trimG(&path)); 510 logD(BLD GRN"mkdir" RST); 511 lv(path); 512 pError0(mkdirParents(path)); 513 pError0(fileChmod(path, *filemode)); 514 } 515 elif (*command == 2) { 516 // send files to client 517 518 if (svrInfo) { 519 // this server is a relay, connect to destination 520 if (not connectToDest(svrInfo)) { 521 logE("Relay: Can't connect to destination %m", svrInfo); 522 ret; 523 } 524 relay_netframe = allocNetFrame(); 525 // forward data from client to destination 526 closeDestConnection = no; 527 o(relay_netframe,send , relay_ssl, receiveB, sz); 528 529 cleanAllocateNetFrame(netframe); 530 531 o(relay_netframe, setCallback, relayForwardDataToClient, netframe /*context*/); 532 533 var r = o(relay_netframe,receive, relay_ssl); 534 logVarG(r); 535 536 // close client connection 537 o(netframe,end, ssl); 538 ret; 539 } 540 541 // check packet size, sendFile path has to be at least 1 byte 542 if (sz < (1/*command*/ + 8/*token*/ + 2 /*sendFileLength*/ + 1 /*sendFile*/)) ret; 543 logD("send files to client"); 544 u16 *sendFileLength = (u16*)(receiveB + 9); 545 if (*sendFileLength > 4096) ret; 546 // check that sendFileLength is correct 547 if (sz < (1/*command*/ + 8/*token*/ + 2 /*sendFileLength*/ + *sendFileLength)) ret; 548 cleanCharP(sendFile) = malloc(*sendFileLength + 1); 549 memcpy(sendFile, receiveB + 11, *sendFileLength); 550 sendFile[*sendFileLength] = 0; 551 552 pErrorNULL(prependG(&sendFile, '/')); 553 pErrorNULL(prependG(&sendFile, root)); 554 pErrorNULL(normalizePathG(&sendFile)); 555 pErrorNULL(trimG(&sendFile)); 556 lv(sendFile); 557 cleanCharP(nroot) = normalizePathG(root); 558 if (not startsWithG(sendFile, nroot)) { 559 logE("Incorrect path, outside home directory: "BLD YLW"%s"RST,sendFile); 560 ret; 561 } 562 563 // send a file or glob 564 565 cleanAllocateSmallArray(pathToSend); 566 567 if (isPath(sendFile)) { 568 pushG(pathToSend, sendFile); 569 } 570 else { 571 // check if sendFile is a glob 572 glob_t globbuf = init0Var; 573 glob(sendFile, 0, NULL, &globbuf); 574 if (!globbuf.gl_pathv) { 575 logE("Incorrect path: "BLD YLW"%s"RST,sendFile); 576 ret; 577 } 578 forEachS(globbuf.gl_pathv, s) { 579 pushG(pathToSend, s); 580 } 581 globfree(&globbuf); 582 } 583 584 cleanAllocateNetFrame(netframe); 585 586 // network buffer 587 u8 buf[1024*1024] = init0Var; 588 589 cleanAllocateSmallDict(recusive); 590 591 iter(pathToSend, P) { 592 castS(p, P); 593 char *sendFile = ssGet(P); 594 595 // create local directory in client 596 // add files from local directory to recusive dict, the last element is the local path 597 if (isDirG(p)) { 598 logD("mkdir in client"); 599 600 char *dirname = basename(ssGet(p)); 601 602 u32 bufi = 0; 603 u64 *filesize = null; 604 makeHeader(buf, &bufi, 1 /* command */, null/*svrInfo no need to authenticate the client*/, ssGet(P), dirname/*dest*/, &filesize); 605 606 o(netframe,send , ssl, buf, bufi); 607 608 var dir = readDirAllG(rtSmallArrayt, p); 609 //lv(dir); 610 if (not isEmptyG(dir)) { 611 // save local path in last element 612 pushG(dir, ssGet(p)); 613 setNFreeG(recusive, dirname, dir); 614 } 615 lv(recusive); 616 continue; 617 } 618 619 // send 620 u32 bufi = 0; 621 u64 *filesize = null; 622 makeHeader(buf, &bufi, 0 /* command */, null/*svrInfo no need to authenticate the client*/, sendFile, null/*destPath is already selected in client*/, &filesize); 623 624 if (*filesize < (sizeof(buf) - bufi)) { 625 // the file is smaller than the network buffer, send all in one go 626 pError0(bReadFile(sendFile, buf + bufi)); 627 o(netframe,send , ssl, buf, bufi + *filesize); 628 } 629 else { 630 logD("big file"); 631 // loop to send big file in chunks 632 u64 szToSend = *filesize; 633 u8 *b = buf + bufi; 634 u64 bSz = sizeof(buf) - bufi; 635 int fd = open(sendFile, O_RDONLY); 636 do { 637 if (szToSend <= bSz) { 638 read(fd, b, szToSend); 639 o(netframe,send , ssl, b, szToSend); 640 szToSend = 0; 641 } 642 else { 643 read(fd, b, bSz); 644 if (szToSend == *filesize) { 645 o(netframe,send , ssl, buf, bufi + bSz); 646 } 647 else { 648 o(netframe,send , ssl, b, bSz); 649 } 650 szToSend -= bSz; 651 } 652 } while(szToSend); 653 close(fd); 654 } 655 } // sendFile or globbing 656 657 // send files recursively 658 // each key is a path in server corresponding to a local directory 659 // the element is the list of files in the directory 660 // it is similar to the iter(pathToSend, P) loop 661 662 iter(recusive, A) { 663 cast(smallArrayt*,a,A); 664 cleanCharP(localPath) = cropElemG(a, rtChar, -1); 665 lv(localPath); 666 iter(a, P) { 667 castS(p, P); 668 char *sendFile = ssGet(P); 669 670 // create local directory in server 671 // add files from local directory to recusive dict, the last element is the local path 672 cleanCharP(localp) = catS(localPath, "/", ssGet(p)); 673 if (isDirG(localp)) { 674 logD("mkdir in client"); 675 cleanCharP(dirname) = catS(iK(recusive), "/", ssGet(p)); 676 677 u32 bufi = 0; 678 u64 *filesize = null; 679 makeHeader(buf, &bufi, 1 /* command */, null/*svrInfo no need to authenticate the client*/, localp, dirname, &filesize); 680 681 o(netframe,send , ssl, buf, bufi); 682 683 var dir = readDirAllG(rtSmallArrayt, localp); 684 lv(dir); 685 if (not isEmptyG(dir)) { 686 // save local path in last element 687 pushG(dir, localp); 688 setNFreeG(recusive, dirname, dir); 689 } 690 //lv(recusive); 691 continue; 692 } 693 694 logD("Send localp file to iK(recusive) client directory"); 695 // send 696 u32 bufi = 0; 697 u64 *filesize = null; 698 makeHeader(buf, &bufi, 0 /* command */, null/*svrInfo no need to authenticate the client*/, localp, (char*)iK(recusive) /*dest*/, &filesize); 699 700 if (*filesize < (sizeof(buf) - bufi)) { 701 // the file is smaller than the network buffer, send all in one go 702 pError0(bReadFile(localp, buf + bufi)); 703 o(netframe,send , ssl, buf, bufi + *filesize); 704 } 705 else { 706 logD("big file"); 707 // loop to send big file in chunks 708 u64 szToSend = *filesize; 709 u8 *b = buf + bufi; 710 u64 bSz = sizeof(buf) - bufi; 711 int fd = open(localp, O_RDONLY); 712 do { 713 if (szToSend <= bSz) { 714 read(fd, b, szToSend); 715 o(netframe,send , ssl, b, szToSend); 716 szToSend = 0; 717 } 718 else { 719 read(fd, b, bSz); 720 if (szToSend == *filesize) { 721 o(netframe,send , ssl, buf, bufi + bSz); 722 } 723 else { 724 o(netframe,send , ssl, b, bSz); 725 } 726 szToSend -= bSz; 727 } 728 } while(szToSend); 729 close(fd); 730 } 731 } 732 } 733 734 lv(recusive); 735 736 // last frame size 0 737 // close connection 738 o(netframe,end, ssl); 739 } 740 } 741 else { 742 // receive large files packetCount > 0 743 if (fd == -1) ret; 744 // big file 745 int r = write(fd, receiveB, sz); 746 if (r == -1) { 747 logE("cant write"); 748 ret; 749 } 750 if (transferSz <= sz) { 751 transferSz = 0; 752 close(fd); 753 fd = -1; 754 packetCount = 0; 755 } 756 else transferSz -= sz; 757 } 758 } 759 760 bool relayForwardDataToClient(void *receiveB, size_t sz, void *context) { 761 cast(netFramet*, netframe, context); 762 // forward data from destination to client 763 o(netframe,send , ssl, receiveB, sz); 764 ret yes; 765 } 766 // vim: set expandtab ts=2 sw=2: