Skip to content

Instantly share code, notes, and snippets.

@nakst
Created December 26, 2023 16:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nakst/1def6b19062c66f8b4c61ec9566dabd3 to your computer and use it in GitHub Desktop.
Save nakst/1def6b19062c66f8b4c61ec9566dabd3 to your computer and use it in GitHub Desktop.
#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