static void psync_p2p_check(const packet_check *packet){ unsigned char hashhex[PSYNC_HASH_DIGEST_HEXLEN], hashsource[PSYNC_HASH_BLOCK_SIZE], hashbin[PSYNC_HASH_DIGEST_LEN]; packet_check_resp resp; if (!memcmp(packet->computername, computername, PSYNC_HASH_DIGEST_HEXLEN)) return; if (psync_p2p_has_file(packet->hashstart, packet->genhash, packet->rand, packet->filesize, hashhex)) resp.type=P2P_RESP_HAVEIT; else if (psync_p2p_is_downloading(packet->hashstart, packet->genhash, packet->rand, packet->filesize, hashhex)) resp.type=P2P_RESP_WAIT; else return; resp.port=tcpport; psync_ssl_rand_weak(resp.rand, sizeof(resp.rand)); memcpy(hashsource, hashhex, PSYNC_HASH_DIGEST_HEXLEN); memcpy(hashsource+PSYNC_HASH_DIGEST_HEXLEN, resp.rand, sizeof(resp.rand)); psync_hash(hashsource, PSYNC_HASH_BLOCK_SIZE, hashbin); psync_binhex(resp.genhash, hashbin, PSYNC_HASH_DIGEST_LEN); debug(D_NOTICE, "replying with %u to a check from %s, looking for %."NTO_STR(PSYNC_HASH_DIGEST_HEXLEN)"s", (unsigned int)resp.type, p2p_get_peer_address(), hashhex); if (files_serving) psync_milisleep(files_serving*10); if (resp.type==P2P_RESP_WAIT) psync_milisleep(PSYNC_P2P_INITIAL_TIMEOUT/4); if (!sendto(udpsock, (const char *)&resp, sizeof(resp), 0, (const struct sockaddr *)&paddr, paddrlen)) debug(D_WARNING, "sendto to %s failed", p2p_get_peer_address()); }
static void status_change_thread(void *ptr){ pstatus_change_callback_t callback=(pstatus_change_callback_t)ptr; while (1){ psync_milisleep(5); pthread_mutex_lock(&statusmutex); while (!statuschanges) pthread_cond_wait(&statuscond, &statusmutex); statuschanges=0; pthread_mutex_unlock(&statusmutex); if (!psync_do_run) break; callback(&psync_status); } }
static void status_change_thread(void *ptr){ char downloadstr[MAX_STATUS_STR_LEN], uploadstr[MAX_STATUS_STR_LEN]; pstatus_change_callback_t callback=(pstatus_change_callback_t)ptr; while (1){ // Maximum 2 updates/sec psync_milisleep(500); pthread_mutex_lock(&statusmutex); while (statuschanges<=0){ statuschanges=-1; pthread_cond_wait(&statuscond, &statusmutex); } statuschanges=0; if (((status_old.filestodownload > 0 ) && (psync_status.filestodownload == 0)) || ((psync_status.filestodownload > 0 ) && (status_old.filestodownload == 0)) || ((status_old.filestoupload > 0 ) && (psync_status.filestoupload == 0)) || ((psync_status.filestoupload > 0 ) && (status_old.filestoupload == 0)) || ((psync_status.localisfull != status_old.localisfull)) || ((psync_status.remoteisfull != status_old.remoteisfull)) || ((psync_status.status != status_old.status) && ( (psync_status.status == PSTATUS_STOPPED) || (psync_status.status == PSTATUS_PAUSED) || (psync_status.status == PSTATUS_OFFLINE) || (status_old.status == PSTATUS_STOPPED) || (status_old.status == PSTATUS_PAUSED) || (status_old.status == PSTATUS_OFFLINE) ) ) ) psync_run_ratelimited("Rebuild icons.", psync_rebuild_icons, 1, 1); status_old = psync_status; pthread_mutex_unlock(&statusmutex); if (!psync_do_run) break; status_fill_formatted_str(&psync_status, downloadstr, uploadstr); debug(D_NOTICE, "sending status update, dwlstr: %s, uplstr: %s", psync_status.downloadstr, psync_status.uploadstr); callback(&psync_status); } }
int psync_p2p_check_download(psync_fileid_t fileid, const unsigned char *filehashhex, uint64_t fsize, const char *filename){ struct sockaddr_in6 addr; fd_set rfds; packet_check pct1; packet_get pct2; packet_check_resp resp; struct timeval tv; psync_interface_list_t *il; psync_socket_t *sockets; size_t i, tlen; psync_socket_t sock, msock; packet_resp_t bresp; unsigned char hashsource[PSYNC_HASH_BLOCK_SIZE], hashbin[PSYNC_HASH_DIGEST_LEN], hashhex[PSYNC_HASH_DIGEST_HEXLEN]; unsigned char *token; socklen_t slen; int sret; if (!psync_setting_get_bool(_PS(p2psync))) return PSYNC_NET_PERMFAIL; debug(D_NOTICE, "sending P2P_CHECK for file with hash %."NTO_STR(PSYNC_HASH_DIGEST_HEXLEN)"s", filehashhex); pct1.type=P2P_CHECK; memcpy(pct1.hashstart, filehashhex, PSYNC_P2P_HEXHASH_BYTES); pct1.filesize=fsize; psync_ssl_rand_weak(pct1.rand, sizeof(pct1.rand)); memcpy(hashsource, filehashhex, PSYNC_HASH_DIGEST_HEXLEN); memcpy(hashsource+PSYNC_HASH_DIGEST_HEXLEN, pct1.rand, sizeof(pct1.rand)); psync_hash(hashsource, PSYNC_HASH_BLOCK_SIZE, hashbin); psync_binhex(pct1.genhash, hashbin, PSYNC_HASH_DIGEST_LEN); memcpy(pct1.computername, computername, PSYNC_HASH_DIGEST_HEXLEN); il=psync_list_ip_adapters(); sockets=psync_new_cnt(psync_socket_t, il->interfacecnt); FD_ZERO(&rfds); msock=0; for (i=0; i<il->interfacecnt; i++){ sockets[i]=INVALID_SOCKET; sock=psync_create_socket(il->interfaces[i].address.ss_family, SOCK_DGRAM, IPPROTO_UDP); if (unlikely(sock==INVALID_SOCKET)){ debug(D_NOTICE, "could not create a socket for address family %u", (unsigned)il->interfaces[i].address.ss_family); continue; } setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *)&on, sizeof(on)); if (unlikely_log(bind(sock, (struct sockaddr *)&il->interfaces[i].address, il->interfaces[i].addrsize)==SOCKET_ERROR)){ psync_close_socket(sock); continue; } if (il->interfaces[i].broadcast.ss_family==AF_INET) ((struct sockaddr_in *)(&il->interfaces[i].broadcast))->sin_port=htons(PSYNC_P2P_PORT); else if (il->interfaces[i].broadcast.ss_family==AF_INET6) ((struct sockaddr_in6 *)(&il->interfaces[i].broadcast))->sin6_port=htons(PSYNC_P2P_PORT); if (sendto(sock, (const char *)&pct1, sizeof(pct1), 0, (struct sockaddr *)&il->interfaces[i].broadcast, il->interfaces[i].addrsize)!=SOCKET_ERROR){ sockets[i]=sock; FD_SET(sock, &rfds); if (sock>=msock) msock=sock+1; } else psync_close_socket(sock); } if (unlikely_log(!msock)) goto err_perm; tv.tv_sec=PSYNC_P2P_INITIAL_TIMEOUT/1000; tv.tv_usec=(PSYNC_P2P_INITIAL_TIMEOUT%1000)*1000; sret=select(msock, &rfds, NULL, NULL, &tv); if (sret==0 || unlikely_log(sret==SOCKET_ERROR)) goto err_perm; bresp=P2P_RESP_NOPE; for (i=0; i<il->interfacecnt; i++) if (sockets[i]!=INVALID_SOCKET && FD_ISSET(sockets[i], &rfds)){ slen=sizeof(addr); sret=recvfrom(sockets[i], (char *)&resp, sizeof(resp), 0, (struct sockaddr *)&addr, &slen); if (unlikely_log(sret==SOCKET_ERROR) || unlikely_log(sret<sizeof(resp))) continue; if (!memcmp(pct1.rand, resp.rand, sizeof(resp.rand))){ debug(D_WARNING, "clients are supposed to generate random data, not to reuse mine"); continue; } memcpy(hashsource, filehashhex, PSYNC_HASH_DIGEST_HEXLEN); memcpy(hashsource+PSYNC_HASH_DIGEST_HEXLEN, resp.rand, sizeof(resp.rand)); psync_hash(hashsource, PSYNC_HASH_BLOCK_SIZE, hashbin); psync_binhex(hashhex, hashbin, PSYNC_HASH_DIGEST_LEN); if (unlikely_log(memcmp(hashhex, resp.genhash, PSYNC_HASH_DIGEST_HEXLEN))) continue; if (resp.type==P2P_RESP_HAVEIT){ debug(D_NOTICE, "got P2P_RESP_HAVEIT"); bresp=P2P_RESP_HAVEIT; break; } else if (resp.type==P2P_RESP_WAIT && bresp==P2P_RESP_NOPE) bresp=P2P_RESP_WAIT; } for (i=0; i<il->interfacecnt; i++) if (sockets[i]!=INVALID_SOCKET) psync_close_socket(sockets[i]); psync_free(il); psync_free(sockets); if (bresp==P2P_RESP_NOPE) goto err_perm2; else if (bresp==P2P_RESP_WAIT){ psync_milisleep(PSYNC_P2P_SLEEP_WAIT_DOWNLOAD); goto err_temp2; } if (psync_p2p_check_rsa()) goto err_perm2; sret=psync_p2p_get_download_token(fileid, filehashhex, fsize, &token, &tlen); debug(D_NOTICE, "got token"); if (unlikely_log(sret!=PSYNC_NET_OK)){ if (sret==PSYNC_NET_TEMPFAIL) goto err_temp2; else goto err_perm2; } if (addr.sin6_family==AF_INET6){ sock=psync_create_socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); addr.sin6_port=htons(resp.port); } else if (addr.sin6_family==AF_INET){ sock=psync_create_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); ((struct sockaddr_in *)&addr)->sin_port=htons(resp.port); } else{ debug(D_ERROR, "unknown address family %u", (unsigned)addr.sin6_family); goto err_perm2; } if (unlikely_log(sock==INVALID_SOCKET)) goto err_perm3; if (unlikely(connect(sock, (struct sockaddr *)&addr, slen)==SOCKET_ERROR)){ debug(D_WARNING, "could not connect to %s port %u", p2p_get_address(&addr), (unsigned)resp.port); goto err_perm3; } debug(D_NOTICE, "connected to peer"); pct2.type=P2P_GET; memcpy(pct2.hashstart, filehashhex, PSYNC_P2P_HEXHASH_BYTES); pct2.filesize=fsize; pct2.keylen=psync_rsa_public_bin->datalen; pct2.tokenlen=tlen; memcpy(pct2.rand, pct1.rand, sizeof(pct1.rand)); memcpy(pct2.genhash, pct1.genhash, sizeof(pct1.genhash)); memcpy(pct2.computername, computername, PSYNC_HASH_DIGEST_HEXLEN); if (socket_write_all(sock, &pct2, sizeof(pct2)) || socket_write_all(sock, psync_rsa_public_bin->data, psync_rsa_public_bin->datalen) || socket_write_all(sock, token, tlen)){ debug(D_WARNING, "writing to socket failed"); goto err_temp3; } psync_free(token); sret=psync_p2p_download(sock, fileid, filehashhex, fsize, filename); psync_close_socket(sock); return sret; err_perm3: psync_free(token); goto err_perm2; err_perm: for (i=0; i<il->interfacecnt; i++) if (sockets[i]!=INVALID_SOCKET) psync_close_socket(sockets[i]); psync_free(il); psync_free(sockets); err_perm2: return PSYNC_NET_PERMFAIL; err_temp3: psync_close_socket(sock); psync_free(token); err_temp2: return PSYNC_NET_TEMPFAIL; }
static void psync_p2p_thread(){ ssize_t ret; char buff[2048]; /* struct sockaddr_in6 addr; */ struct sockaddr_in addr4; psync_socket_t tcpsock, socks[2], *inconn; socklen_t sl; int sret; psync_wait_statuses_array(requiredstatuses, ARRAY_SIZE(requiredstatuses)); tcpsock=INVALID_SOCKET; /* udpsock=psync_create_socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); if (unlikely_log(udpsock==INVALID_SOCKET)){*/ udpsock=psync_create_socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (unlikely_log(udpsock==INVALID_SOCKET)) goto ex; setsockopt(udpsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); memset(&addr4, 0, sizeof(addr4)); addr4.sin_family=AF_INET; addr4.sin_port =htons(PSYNC_P2P_PORT); addr4.sin_addr.s_addr=INADDR_ANY; if (unlikely_log(bind(udpsock, (struct sockaddr *)&addr4, sizeof(addr4))==SOCKET_ERROR)) goto ex; /* } else{ setsockopt(udpsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); memset(&addr, 0, sizeof(addr)); addr.sin6_family=AF_INET6; addr.sin6_port =htons(PSYNC_P2P_PORT); addr.sin6_addr =in6addr_any; if (unlikely_log(bind(udpsock, (struct sockaddr *)&addr, sizeof(addr))==SOCKET_ERROR)) goto ex; } tcpsock=psync_create_socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP); if (unlikely_log(tcpsock==INVALID_SOCKET)){*/ tcpsock=psync_create_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (unlikely_log(tcpsock==INVALID_SOCKET)) goto ex; setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); memset(&addr4, 0, sizeof(addr4)); addr4.sin_family=AF_INET; addr4.sin_port =htons(0); addr4.sin_addr.s_addr=INADDR_ANY; if (unlikely_log(bind(tcpsock, (struct sockaddr *)&addr4, sizeof(addr4))==SOCKET_ERROR)) goto ex; sl=sizeof(addr4); if (unlikely_log(getsockname(tcpsock, (struct sockaddr *)&addr4, &sl)==SOCKET_ERROR)) goto ex; tcpport=ntohs(addr4.sin_port); /* } else{ setsockopt(tcpsock, SOL_SOCKET, SO_REUSEADDR, (const char *)&on, sizeof(on)); memset(&addr, 0, sizeof(addr)); addr.sin6_family=AF_INET6; addr.sin6_port =htons(0); addr.sin6_addr =in6addr_any; if (unlikely_log(bind(tcpsock, (struct sockaddr *)&addr, sizeof(addr))==SOCKET_ERROR)) goto ex; sl=sizeof(addr); if (unlikely_log(getsockname(tcpsock, (struct sockaddr *)&addr, &sl)==SOCKET_ERROR)) goto ex; tcpport=ntohs(addr.sin6_port); }*/ if (unlikely_log(listen(tcpsock, 2))) goto ex; socks[0]=udpsock; socks[1]=tcpsock; while (psync_do_run){ if (unlikely(!psync_setting_get_bool(_PS(p2psync)))){ pthread_mutex_lock(&p2pmutex); if (!psync_setting_get_bool(_PS(p2psync))){ running=0; psync_close_socket(tcpsock); psync_close_socket(udpsock); pthread_mutex_unlock(&p2pmutex); return; } pthread_mutex_unlock(&p2pmutex); } psync_wait_statuses_array(requiredstatuses, ARRAY_SIZE(requiredstatuses)); sret=psync_select_in(socks, 2, -1); if (unlikely_log(sret==-1)){ psync_milisleep(1); continue; } if (sret==0){ paddrlen=sizeof(paddr); ret=recvfrom(udpsock, buff, sizeof(buff), 0, (struct sockaddr *)&paddr, &paddrlen); if (likely_log(ret!=SOCKET_ERROR)) psync_p2p_process_packet(buff, ret); else psync_milisleep(1); } else if (sret==1){ inconn=psync_new(psync_socket_t); *inconn=accept(tcpsock, NULL, NULL); if (unlikely_log(*inconn==INVALID_SOCKET)) psync_free(inconn); else psync_run_thread1("p2p tcp", psync_p2p_tcphandler, inconn); } } ex: pthread_mutex_lock(&p2pmutex); running=0; psync_close_socket(tcpsock); psync_close_socket(udpsock); pthread_mutex_unlock(&p2pmutex); }