Пример #1
0
void pingClient_sendPing(PingClient *pingClient) {
    struct timespec now;
    clock_gettime(CLOCK_REALTIME, &now);

    GString *buf = g_string_new("");
    while(buf->len < pingClient->pingSize) {
        g_string_append_printf(buf, "TOR-COOKIE: %8.8X\r\nTIME: %lu\r\n\r\n", pingClient->cookie, TIME_TO_NS(now));
    }

    gint sockd = pingClient->sockd;
    for(gint i = 0; i < 1; i++) {
        gint bytes = send(sockd, buf->str,  pingClient->pingSize, 0);
        //PING_CLIENT_ASSERTIO(ping, bytes, errno == EWOULDBLOCK || errno == ENOTCONN || errno == EALREADY, PING_CLIENT_ERR_SEND);
        if(bytes < 0 && errno != EWOULDBLOCK && errno != ENOTCONN && errno != EALREADY) {
            pingClient_shutdown(pingClient);
            pingClient_start(pingClient, pingClient->epolld, pingClient->socksAddr, pingClient->socksPort,
                             pingClient->serverAddr, pingClient->serverPort, pingClient->pingInterval, pingClient->pingSize);

            /* set wakeup timer and call sleep function */
            pingClient->createCallback((ShadowPluginCallbackFunc)pingClient_wakeup, pingClient, 60);
        } else {
            gint64 nanoseconds = TIME_TO_NS(now);
            g_queue_push_tail(pingClient->pingTimes, (gpointer)nanoseconds);
            pingClient->pingsSent++;
            pingClient->createCallback(pingClient_sendPing, pingClient, (guint)pingClient->pingInterval);
        }
    }
    g_string_free(buf, TRUE);

}
Пример #2
0
gint torrentClient_activate(TorrentClient *tc, gint sockd, gint events) {
	gchar buf[TC_BUF_SIZE];
	ssize_t bytes;
	enum torrentClient_code ret = TC_SUCCESS;

	TorrentClient_Server* server = g_hash_table_lookup(tc->connections, &sockd);
	if(server == NULL) {
		return TC_ERR_NOSERVER;
	}

	start:
	switch(server->state) {
		case TC_SOCKS_REQUEST_INIT: {
			/* check that we actually have FT_SOCKS_INIT_LEN space */
			assert(sizeof(server->buf) - server->buf_write_offset >= TC_SOCKS_INIT_LEN);

			/* write the request to our buffer */
			memcpy(server->buf + server->buf_write_offset, TC_SOCKS_INIT, TC_SOCKS_INIT_LEN);

			server->buf_write_offset += TC_SOCKS_INIT_LEN;

			/* we are ready to send, then transition to socks init reply */
			server->state = TC_SEND;
			server->nextstate = TC_SOCKS_TOREPLY_INIT;

			torrentClient_changeEpoll(tc, sockd, EPOLLOUT);

			goto start;
		}

		case TC_SOCKS_TOREPLY_INIT: {
			torrentClient_changeEpoll(tc, sockd, EPOLLIN);
			server->state = TC_RECEIVE;
			server->nextstate = TC_SOCKS_REPLY_INIT;
			goto start;
		}

		case TC_SOCKS_REPLY_INIT: {
			/* if we didnt get it all, go back for more */
			if(server->buf_write_offset - server->buf_read_offset < 2) {
				server->state = TC_SOCKS_TOREPLY_INIT;
				goto start;
			}

			/* must be version 5 */
			if(server->buf[server->buf_read_offset] != 0x05) {
				return TC_ERR_SOCKSINIT;
			}
			/* must be success */
			if(server->buf[server->buf_read_offset + 1] != 0x00) {
				return TC_ERR_SOCKSINIT;
			}

			server->buf_read_offset += 2;

			/* now send the socks connection request */
			server->state = TC_SOCKS_REQUEST_CONN;

			goto start;
		}

		case TC_SOCKS_REQUEST_CONN: {
			/* check that we actually have TC_SOCKS_REQ_HEAD_LEN+6 space */
			assert(sizeof(server->buf) - server->buf_write_offset >= TC_SOCKS_REQ_HEAD_LEN + 6);

			in_addr_t addr = server->addr;
			in_port_t port = htons(server->port);

			/* write connection request, including intended destination */
			memcpy(server->buf + server->buf_write_offset, TC_SOCKS_REQ_HEAD, TC_SOCKS_REQ_HEAD_LEN);
			server->buf_write_offset += TC_SOCKS_REQ_HEAD_LEN;
			memcpy(server->buf + server->buf_write_offset, &(addr), 4);
			server->buf_write_offset += 4;
			memcpy(server->buf + server->buf_write_offset, &(port), 2);
			server->buf_write_offset += 2;

			/* we are ready to send, then transition to socks conn reply */
			server->state = TC_SEND;
			server->nextstate = TC_SOCKS_TOREPLY_CONN;
			torrentClient_changeEpoll(tc, sockd, EPOLLOUT);

			goto start;
		}

		case TC_SOCKS_TOREPLY_CONN: {
			torrentClient_changeEpoll(tc, sockd, EPOLLIN);
			server->state = TC_RECEIVE;
			server->nextstate = TC_SOCKS_REPLY_CONN;
			goto start;
		}

		case TC_SOCKS_REPLY_CONN: {
			/* if we didnt get it all, go back for more */
			if(server->buf_write_offset - server->buf_read_offset < 10) {
				server->state = TC_SOCKS_TOREPLY_CONN;
				goto start;
			}

			/* must be version 5 */
			if(server->buf[server->buf_read_offset] != 0x05) {
				return TC_ERR_SOCKSCONN;
			}

			/* must be success */
			if(server->buf[server->buf_read_offset + 1] != 0x00) {
				return TC_ERR_SOCKSCONN;
			}

			/* check address type for IPv4 */
			if(server->buf[server->buf_read_offset + 3] != 0x01) {
				return TC_ERR_SOCKSCONN;
			}

			/* get address server told us */
			in_addr_t socks_bind_addr;
			in_port_t socks_bind_port;
			memcpy(&socks_bind_addr, &(server->buf[server->buf_read_offset + 4]), 4);
			memcpy(&socks_bind_port, &(server->buf[server->buf_read_offset + 8]), 2);

			server->buf_read_offset += 10;

			/* if we were send a new address, we need to reconnect there */
			if(socks_bind_addr != 0 && socks_bind_port != 0) {
				/* reconnect at new address */
				close(tc->sockd);
				if(torrentClient_connect(tc, socks_bind_addr, socks_bind_port) != TC_SUCCESS) {
					return TC_ERR_SOCKSCONN;
				}
			}

			/* now we are ready to send the http request */
			server->state = TC_SERVER_REQUEST;
			server->nextstate = TC_SERVER_REQUEST;

			torrentClient_changeEpoll(tc, sockd, EPOLLOUT);

			goto start;
		}

		case TC_SEND: {
			assert(server->buf_write_offset >= server->buf_read_offset);

			gpointer sendpos = server->buf + server->buf_read_offset;
			size_t sendlen = server->buf_write_offset - server->buf_read_offset;

			ssize_t bytes = send(sockd, sendpos, sendlen, 0);

			TC_ASSERTIO(tc, bytes, errno == EWOULDBLOCK || errno == ENOTCONN || errno == EALREADY, TC_ERR_SEND);

			server->buf_read_offset += bytes;

			if(server->buf_read_offset == server->buf_write_offset) {
				/* we've sent everything we can, reset offsets */
				server->buf_read_offset = 0;
				server->buf_write_offset = 0;

				/* now we go to the next state */
				server->state = server->nextstate;
			}

			/* either next state or try to send more */
			goto start;
		}

		case TC_RECEIVE: {
			size_t space = sizeof(server->buf) - server->buf_write_offset;

			/* we will recv from socket and write to buf */
			gpointer recvpos = server->buf + server->buf_write_offset;
			ssize_t bytes = recv(sockd, recvpos, space, 0);

			TC_ASSERTIO(tc, bytes, errno == EWOULDBLOCK, TC_ERR_RECV);

			server->buf_write_offset += bytes;

			/* go to the next state to check new data */
			server->state = server->nextstate;

			goto start;
		}

//		case TC_AUTH_REGISTER:
//			buf[0] = 0x01;
//			memcpy(&buf[1], &(tc->serverPort), sizeof(tc->serverPort));
//
//			bytes = send(sockd, buf, sizeof(tc->serverPort) + 1, 0);
//			TC_ASSERTIO(tc, bytes, errno == EWOULDBLOCK || errno == ENOTCONN || errno == EALREADY, TC_ERR_SEND);
//
//			torrentClient_changeEpoll(tc, sockd, EPOLLIN);
//			server->state = TC_AUTH_REQUEST_NODES;
//			//break;


		case TC_AUTH_REQUEST_NODES:
			buf[0] = TA_MSG_REQUEST_NODES;
			bytes = send(sockd, buf, 1, 0);
			TC_ASSERTIO(tc, bytes, errno == EWOULDBLOCK || errno == ENOTCONN || errno == EALREADY, TC_ERR_SEND);
			torrentClient_changeEpoll(tc, sockd, EPOLLIN);
			server->state = TC_AUTH_RECEIVE_NODES;
			break;

		case TC_AUTH_RECEIVE_NODES:
			bytes = recv(sockd, buf, 1024, 0);
			TC_ASSERTIO(tc, bytes, errno == EWOULDBLOCK, TC_ERR_RECV);
			gint numNodes = buf[0];
			gint offset = 1;
			for(int i = 0; i < numNodes; i++) {
				in_addr_t addr;
				in_port_t port;

				memcpy(&addr, buf + offset, sizeof(addr));
				offset += sizeof(addr);
				memcpy(&port, buf + offset, sizeof(port));
				offset += sizeof(port);

				int found = 0;
				GList *currItem = tc->servers;
				while(!found && currItem != NULL) {
					TorrentClient_Server *server = currItem->data;
					if(server->addr == addr && server->port == port) {
						found = 1;
					}
					currItem = g_list_next(currItem);
				}

				if(!found) {
					TorrentClient_Server* server = g_new0(TorrentClient_Server, 1);
					server->addr = addr;
					server->port = port;
					if(tc->socksAddr == htonl(INADDR_NONE)) {
						server->sockd = torrentClient_connect(tc, server->addr, htons(server->port));
						server->state = TC_SERVER_REQUEST;
					} else {
						server->sockd = torrentClient_connect(tc, tc->socksAddr, tc->socksPort);
						server->state = TC_SOCKS_REQUEST_INIT;
					}
					server->cookie = rand() % G_MAXUINT;

					if(server->sockd < 0) {
						return TC_ERR_CONNECT;
					}

					server->downBytesTransfered = 0;
					server->upBytesTransfered = 0;
					server->buf_read_offset = 0;
					server->buf_write_offset = 0;
					torrentClient_changeEpoll(tc, server->sockd, EPOLLOUT);
					tc->servers = g_list_append(tc->servers, server);
					g_hash_table_insert(tc->connections, &(server->sockd), server);
				}
			}
			clock_gettime(CLOCK_REALTIME, &tc->lastServerListFetch);

			torrentClient_changeEpoll(tc, sockd, EPOLLIN);
			server->state = TC_AUTH_RECEIVE_NODES;

			break;

		case TC_SERVER_REQUEST:
			if(tc->totalBytesDown == 0) {
				clock_gettime(CLOCK_REALTIME, &(tc->download_start));
			}

			if(tc->blocksRemaining <= 0) {
				server->state = TC_SERVER_IDLE;
				torrentClient_changeEpoll(tc, sockd, EPOLLIN);
				break;
			}

			gchar request[64];
			sprintf(request, "FILE REQUEST\r\nTOR-COOKIE: %8.8X\r\n", server->cookie);

			bytes = send(sockd, request, strlen(request), 0);
			TC_ASSERTIO(tc, bytes, errno == EWOULDBLOCK || errno == ENOTCONN || errno == EALREADY, TC_ERR_SEND);
			torrentClient_changeEpoll(tc, sockd, EPOLLIN);

			tc->blocksRemaining--;

			server->downBytesTransfered = 0;
			server->upBytesTransfered = 0;
			server->buf_read_offset = 0;
			server->buf_write_offset = 0;
			server->state = TC_SERVER_TRANSFER;
			clock_gettime(CLOCK_REALTIME, &(server->download_start));
			break;

		case TC_SERVER_TRANSFER: {
			if(events & EPOLLIN && server->downBytesTransfered < tc->downBlockSize) {
				int remainingBytes = tc->downBlockSize - server->downBytesTransfered;
				int len = (remainingBytes < sizeof(buf) ? remainingBytes : sizeof(buf));
				bytes = recv(sockd, buf, len, 0);
				TC_ASSERTIO(tc, bytes, errno == EWOULDBLOCK, TC_ERR_RECV);

				if(tc->totalBytesDown == 0) {
					clock_gettime(CLOCK_REALTIME, &(tc->download_first_byte));
				}

				if(server->downBytesTransfered == 0) {
					clock_gettime(CLOCK_REALTIME, &(server->download_first_byte));
				}

				server->downBytesTransfered += bytes;
				tc->totalBytesDown += bytes;
				tc->bytesInProgress -= bytes;
			}

			if(events & EPOLLOUT && server->upBytesTransfered < tc->upBlockSize) {
				int remainingBytes = tc->upBlockSize - server->upBytesTransfered;
				int len = (remainingBytes < sizeof(buf) ? remainingBytes : sizeof(buf));

				struct timespec now;
				clock_gettime(CLOCK_REALTIME, &now);
				gchar filler[64];
				sprintf(filler, TC_BUF_FILLER, server->cookie, TIME_TO_NS(now));
				torrentClient_fillBuffer(buf, len, filler);

				bytes = send(sockd, buf, len, 0);
				TC_ASSERTIO(tc, bytes, errno == EWOULDBLOCK || errno == ENOTCONN || errno == EALREADY, TC_ERR_SEND);

				server->upBytesTransfered += bytes;
				tc->totalBytesUp += bytes;
			}

			tc->currentBlockTransfer = server;

			if(server->downBytesTransfered >= tc->downBlockSize && server->upBytesTransfered >= tc->upBlockSize) {
				server->state = TC_SERVER_FINISHED;
				torrentClient_changeEpoll(tc, sockd, EPOLLIN);
			} else if(server->downBytesTransfered >= tc->downBlockSize) {
				torrentClient_changeEpoll(tc, sockd, EPOLLOUT);
			} else if(server->upBytesTransfered >= tc->upBlockSize) {
				torrentClient_changeEpoll(tc, sockd, EPOLLIN);
			}

			break;
		}

		case TC_SERVER_FINISHED: {
			bytes = recv(sockd, buf, sizeof(buf), 0);
			TC_ASSERTIO(tc, bytes, errno == EWOULDBLOCK, TC_ERR_RECV);

			gchar *found = strcasestr(buf, "FINISHED");
			if(found) {
				server->state = TC_SERVER_REQUEST;
				clock_gettime(CLOCK_REALTIME, &(server->download_end));

				tc->currentBlockTransfer = server;
				tc->blocksDownloaded++;
				ret = TC_BLOCK_DOWNLOADED;
				torrentClient_changeEpoll(tc, sockd, EPOLLOUT);
			}
			break;
		}

		default:
			break;
	}

	return ret;
}