// Vonger's simple File transfer // homepage: http://vonger.net/ // compile in windows, output vof.exe: // cl vof.c // compile in macos/linux, output vof: // cc -g vof.c -o vof #ifdef _WIN32 #include #include #pragma comment(lib, "ws2_32.lib") #define close closesocket #define snprintf sprintf_s #define errcode GetLastError() #else #include #include #include #include #include #include #include #define errcode errno #endif #include #include #include #define PORT_BOARDCAST_LISTENER 20720 #define PORT_BOARDCAST_SENDER 20800 #define PORT_SERVER 50000 #define BUFFER_SIZE 512 #define BIND_MAXTIMES 16 #define TASK_PROGTIME 500 #define TASK_HASHSIZE 10000 #define TASK_NAMESIZE 255 #define TASK_BUFFSIZE 255 typedef struct _VOF_TASK { int code; char name[TASK_NAMESIZE]; int size; struct sockaddr_in in; struct _VOF_TASK *next; }VOF_TASK; VOF_TASK *g_task = NULL; VOF_TASK *vof_new_task() { VOF_TASK *task = (VOF_TASK *)malloc(sizeof(VOF_TASK)); memset(task, 0, sizeof(VOF_TASK)); return task; } VOF_TASK *vof_get_task(int code) { VOF_TASK *cur = g_task; while(cur) { if(cur->code == code) return cur; cur = cur->next; } return NULL; } void vof_set_task(VOF_TASK *task) { VOF_TASK *cur = vof_get_task(task->code); if(cur == NULL) { task->next = g_task; g_task = task; } else { strcpy(cur->name, task->name); cur->size = task->size; memcpy(&cur->in, &task->in, sizeof(struct sockaddr_in)); free(task); } } void vof_print_task() { VOF_TASK *cur = g_task; while(cur) { printf("%04d:%d:%s:%s\n", cur->code, cur->size, cur->name, inet_ntoa(cur->in.sin_addr)); cur = cur->next; } } int vof_msecond() { #ifdef _WIN32 return (int)GetTickCount(); #else struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec % 1000 * 1000 + tv.tv_usec / 1000; #endif } void vof_init() { #ifdef _WIN32 WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); #endif } void vof_uninit() { #ifdef _WIN32 WSACleanup(); #endif } int vof_scan_code() { int sock = -1, code = -1, msec = 0, size = 0, b = 1; struct sockaddr_in in; socklen_t len = sizeof(struct sockaddr_in); char buf[TASK_BUFFSIZE] = {0}; VOF_TASK *task = NULL; sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(sock <= 0) { printf("error: can not create socket, code = %d.\n", errcode); return -1; } setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&b, sizeof(int)); memset(&in, 0, sizeof(struct sockaddr_in)); in.sin_family = AF_INET; in.sin_addr.s_addr = htonl(INADDR_ANY); in.sin_port = htons(PORT_BOARDCAST_LISTENER); if(bind(sock, (struct sockaddr *)&in, sizeof(struct sockaddr_in))) { printf("error: can not bind to address, code = %d.\n", errcode); return -1; } msec = vof_msecond(); srand(msec); while(1) { fd_set fds; struct timeval t = {0, 10000}; int max = sock + 1, count = 0; FD_ZERO(&fds); FD_SET(sock, &fds); count = select(max, &fds, NULL, NULL, &t); if(count < 0) { printf("error: can not select socket, code = %d.\n", errcode); return -1; } if(vof_msecond() - msec > 1200) break; if(count == 0) continue; memset(buf, 0, TASK_BUFFSIZE); size = recvfrom(sock, buf, TASK_BUFFSIZE, 0, (struct sockaddr *)&in, &len); if(size <= 0) continue; task = vof_new_task(); sscanf(buf, "%d:%d:%s", &task->code, &task->size, task->name); memcpy(&task->in, &in, len); task->in.sin_port = htons(PORT_SERVER + task->code); vof_set_task(task); } close(sock); code = rand() % TASK_HASHSIZE; while(vof_get_task(code) != NULL) { code++; code = code % 10000; } return code; } int vof_check_code(int code) { vof_scan_code(); if(vof_get_task(code) == NULL) return -1; return code; } int vof_get_size(int code) { VOF_TASK *task = vof_get_task(code); if(task == NULL) return -1; return task->size; } struct sockaddr_in* vof_get_address(int code) { VOF_TASK *task = vof_get_task(code); if(task == NULL) return NULL; return &task->in; } const char *vof_get_name(int code) { VOF_TASK *task = vof_get_task(code); if(task == NULL) return NULL; return task->name; } const char *vof_file_name(const char *path) { int len = strlen(path), i; for(i = len - 1; i >= 0 && path[i] != '\\' && path[i] != '/'; i--); return path + i + 1; } int vofs(const char *path) { struct sockaddr_in in; socklen_t len = sizeof(struct sockaddr_in); FILE *fp = NULL; int code = -1, size = -1, cur = 0, b = 1, c = 0, msec = 0, binds = 0; int socks = -1, sockb = -1, sockc = -1; char buf[BUFFER_SIZE] = {0}; const char *name = NULL; vof_init(); fp = fopen(path, "rb"); if(fp == NULL) { printf("error: can not read target file, code = %d.\n", errcode); return -1; } fseek(fp, 0, SEEK_END); size = ftell(fp); name = vof_file_name(path); code = vof_scan_code(); if(code < 0) return -1; printf("%04d:%d:%s\n", code, size, name); snprintf(buf, BUFFER_SIZE - 1, "%04d:%d:%s", code, size, name); socks = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); sockb = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(socks <= 0 || sockb <= 0) { printf("error: can not create socket, code = %d.\n", errcode); return -1; } setsockopt(sockb, SOL_SOCKET, SO_BROADCAST, (char *)&b, sizeof(int)); setsockopt(sockb, SOL_SOCKET, SO_REUSEADDR, (char *)&b, sizeof(int)); memset(&in, 0, sizeof(struct sockaddr_in)); in.sin_family = AF_INET; in.sin_addr.s_addr = htonl(INADDR_ANY); in.sin_port = htons(PORT_BOARDCAST_SENDER); while(bind(sockb, (struct sockaddr *)&in, sizeof(struct sockaddr_in))) { in.sin_port = htons(ntohs(in.sin_port) + 1); if(binds++ >= BIND_MAXTIMES) { printf("error: can not bind to address, code = %d.\n", errcode); return -1; } } setsockopt(socks, SOL_SOCKET, SO_REUSEADDR, (char *)&b, sizeof(int)); memset(&in, 0, sizeof(struct sockaddr_in)); in.sin_family = AF_INET; in.sin_addr.s_addr = htonl(INADDR_ANY); in.sin_port = htons(PORT_SERVER + code); if(bind(socks, (struct sockaddr *)&in, sizeof(struct sockaddr_in))) { printf("error: can not bind to address, code = %d.\n", errcode); return -1; } if(listen(socks, SOMAXCONN)) { printf("error: can not listen socket, code = %d.\n", errcode); return -1; } while(1) { fd_set fds; struct timeval t = {0, 300000}; int max = socks + 1, count = 0; FD_ZERO(&fds); FD_SET(socks, &fds); count = select(max, &fds, NULL, NULL, &t); if(count == 0 && sockc < 0) { memset(&in, 0, sizeof(struct sockaddr_in)); in.sin_family = AF_INET; in.sin_addr.s_addr = htonl(INADDR_BROADCAST); in.sin_port = htons(PORT_BOARDCAST_LISTENER); if(sendto(sockb, buf, strlen(buf), 0, (const struct sockaddr *)&in, sizeof(struct sockaddr_in)) < 0) { printf("error: can not send boardcast, code = %d\n", errcode); return -1; } continue; } sockc = accept(socks, (struct sockaddr *)&in, &len); close(socks); close(sockb); break; } fseek(fp, 0, SEEK_SET); msec = vof_msecond(); while(size > cur) { c = fread(buf, 1, BUFFER_SIZE, fp); if(c <= 0) { printf("error: can not read file, code = %d.\n", errcode); return -1; } c = send(sockc, buf, c, 0); if(c <= 0) { printf("error: can not send file, code = %d.\n", errcode); return -1; } cur += c; if(vof_msecond() - msec >= TASK_PROGTIME) { printf("%d\n", cur); msec = vof_msecond(); } } printf("%d\n", size); close(sockc); fclose(fp); vof_uninit(); return 1; } int vofr(int code) { struct sockaddr_in *in = NULL; int sock = -1, c = 0, msec = 0, cur = 0, size = 0; char buf[BUFFER_SIZE] = {0}; const char *name = NULL; FILE *fp = NULL; vof_init(); if(vof_check_code(code) < 0) { printf("error: can not find task, code = %d.\n", errcode); return -1; } in = vof_get_address(code); name = vof_get_name(code); size = vof_get_size(code); printf("%04d:%d:%s\n", code, size, name); fp = fopen(name, "wb"); if(fp == NULL) { printf("error: can not open file, code = %d.\n", errcode); return -1; } sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(connect(sock, (const struct sockaddr *)in, sizeof(struct sockaddr_in))) { printf("error: can not connect to server, code = %d.\n", errcode); return -1; } fseek(fp, 0, SEEK_SET); msec = vof_msecond(); while(size > cur) { c = recv(sock, buf, BUFFER_SIZE, 0); if(c <= 0) { printf("error: can not recv file, code = %d.\n", errcode); break; } c = fwrite(buf, 1, c, fp); if(c <= 0) { printf("error: can not write to file, code = %d.\n", errcode); break; } cur += c; if(vof_msecond() - msec >= TASK_PROGTIME) { printf("%d\n", cur); msec = vof_msecond(); } } printf("%d\n", size); close(sock); fclose(fp); vof_uninit(); return 1; } int vof_check_mode(char *param) { if(strlen(param) == 4) { if(param[0] >= '0' && param[0] <= '9' && param[1] >= '0' && param[1] <= '9' && param[2] >= '0' && param[2] <= '9' && param[3] >= '0' && param[3] <= '9') return 1; } return 2; } int main(int argc, char *argv[]) { if(argc != 2) { printf("version: 0.3b\n"); printf("usage: vof [recv:code|send:path]\n"); printf("\nscanning current tasks...\n"); vof_init(); vof_scan_code(); vof_print_task(); vof_uninit(); return 0; } switch(vof_check_mode(argv[1])) { case 1: return vofr(atoi(argv[1])); case 2: return vofs(argv[1]); } printf("error: unknown mode.\n"); return -1; }