Created
December 26, 2023 16:48
-
-
Save nakst/1def6b19062c66f8b4c61ec9566dabd3 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <sys/types.h> | |
#include <time.h> | |
#include <sys/socket.h> | |
#include <netinet/in.h> | |
#include <arpa/inet.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <stdbool.h> | |
#include <ifaddrs.h> | |
#define PORT (23875) | |
#define MAGIC (0x13AE83BD) | |
int Server(FILE *file) { | |
{ | |
struct ifaddrs *addrs, *tmp; | |
getifaddrs(&addrs); | |
tmp = addrs; | |
while (tmp) { | |
if (tmp->ifa_addr && tmp->ifa_addr->sa_family == AF_INET) { | |
struct sockaddr_in *pAddr = (struct sockaddr_in *)tmp->ifa_addr; | |
if (tmp->ifa_name[0] == 'w') { | |
printf("%s: %s\n", tmp->ifa_name, inet_ntoa(pAddr->sin_addr)); | |
} | |
} | |
tmp = tmp->ifa_next; | |
} | |
freeifaddrs(addrs); | |
} | |
int socketHandle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); | |
if (socketHandle == -1) { | |
perror("Socket failed"); | |
return 1; | |
} | |
int enable = 1; | |
setsockopt(socketHandle, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable)); | |
struct sockaddr_in address = { 0 }; | |
address.sin_family = AF_INET; | |
address.sin_port = htons(PORT); | |
address.sin_addr.s_addr = htonl(INADDR_ANY); | |
if (bind(socketHandle, (struct sockaddr *) &address, sizeof(address)) == -1) { | |
perror("Bind failed"); | |
close(socketHandle); | |
return 1; | |
} | |
if (listen(socketHandle, 1) == -1) { | |
perror("Listen failed"); | |
close(socketHandle); | |
return 1; | |
} | |
int connectionHandle = accept(socketHandle, NULL, NULL); | |
if (connectionHandle == -1) { | |
perror("Accept failed"); | |
close(socketHandle); | |
return 1; | |
} | |
uint32_t magic = MAGIC; | |
write(connectionHandle, &magic, sizeof(magic)); | |
while (true) { | |
char buffer[4096]; | |
uint32_t bytesRead = fread(buffer, 1, sizeof(buffer), file); | |
write(connectionHandle, &bytesRead, sizeof(bytesRead)); | |
if (!bytesRead) break; | |
if (bytesRead != write(connectionHandle, buffer, bytesRead)) { | |
printf("Transfer failed (short write).\n"); | |
break; | |
} | |
} | |
shutdown(connectionHandle, SHUT_RDWR); | |
close(connectionHandle); | |
close(socketHandle); | |
return 0; | |
} | |
int Client(FILE *file, int ipLastBit) { | |
int socketHandle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); | |
if (socketHandle == -1) { | |
perror("Socket failed"); | |
return 1; | |
} | |
char ipAddress[32] = "192.168.1."; | |
sprintf(ipAddress + strlen(ipAddress), "%d", ipLastBit); | |
struct sockaddr_in address = { 0 }; | |
address.sin_family = AF_INET; | |
address.sin_port = htons(PORT); | |
inet_pton(AF_INET, ipAddress, &address.sin_addr); | |
if (connect(socketHandle, (struct sockaddr *) &address, sizeof(address)) == -1) { | |
perror("Connect failed"); | |
close(socketHandle); | |
return 1; | |
} | |
bool success = false; | |
uint32_t magic = 0; | |
read(socketHandle, &magic, sizeof(magic)); | |
if (magic != MAGIC) { | |
printf("Error: Magic number mismatch.\n"); | |
close(socketHandle); | |
return 1; | |
} | |
size_t totalWritten = 0; | |
size_t lastReported = 0; | |
uint64_t startTime = time(NULL); | |
while (true) { | |
char buffer[4096]; | |
uint32_t byteCount; | |
size_t bytesRead = read(socketHandle, &byteCount, sizeof(byteCount)); | |
if (bytesRead != sizeof(byteCount) || byteCount > sizeof(buffer)) break; | |
if (byteCount == 0) { success = true; break; } | |
while (byteCount) { | |
bytesRead = read(socketHandle, buffer, byteCount); | |
if (!bytesRead) break; | |
fwrite(buffer, 1, bytesRead, file); | |
totalWritten += bytesRead; | |
byteCount -= bytesRead; | |
if (totalWritten - lastReported > 10000000) { | |
printf("%d MB received...\n", totalWritten / 1000000); | |
lastReported = totalWritten; | |
} | |
} | |
} | |
uint64_t endTime = time(NULL); | |
if (!success) printf("Error: The transfer didn't complete.\n"); | |
else printf("Transfer complete in %d seconds (average speed: %.1f MB/s).\n", (int) (endTime - startTime), | |
(double) totalWritten / (endTime - startTime) / 1000000.0); | |
close(socketHandle); | |
return 0; | |
} | |
int main(int argc, char **argv) { | |
if (argc < 2) { | |
fprintf(stderr, "Usage: %s <send/receive> <options>\n", argv[0]); | |
exit(1); | |
} | |
bool server = 0 == strcmp(argv[1], "send"); | |
if (!server && strcmp(argv[1], "receive")) { | |
fprintf(stderr, "Usage: %s <send/receive> <options>\n", argv[0]); | |
exit(1); | |
} | |
if (server && argc != 3) { | |
fprintf(stderr, "Usage: %s send <file>\n", argv[0]); | |
exit(1); | |
} | |
if (!server && argc != 4) { | |
fprintf(stderr, "Usage: %s receive <file> <ip-last-bit>\n", argv[0]); | |
exit(1); | |
} | |
FILE *f = fopen(argv[2], server ? "rb" : "wb"); | |
if (!f) { | |
fprintf(stderr, "Error: Could not open file '%s'.\n", argv[2]); | |
exit(1); | |
} | |
return server ? Server(f) : Client(f, atoi(argv[3])); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment