示例#1
0
GaduDCCServer::GaduDCCServer( QHostAddress* dccIp, unsigned int port )
:QObject()
{
	kdDebug( 14100 ) << "dcc socket NULL, creating new liteining socket " << endl;

	// don't care about UIN at that point
	dccSock = gg_dcc_socket_create( (unsigned int)-1, port );

	if ( dccSock == NULL ){
		kdDebug(14100) << "attempt to initialize gadu-dcc listeing socket FAILED" << endl;
		return;
	}

	kdDebug(14100) << "attempt to initialize gadu-dcc listeing socket sucess" << endl;

	// using global variables sucks, don't have too much choice thou
	if ( dccIp == NULL ) {
		gg_dcc_ip = 0xffffffff; // 255.255.255.255
	}
	else {
		gg_dcc_ip = htonl( dccIp->ip4Addr() );
	}
	gg_dcc_port = dccSock->port;

	createNotifiers( true );
	enableNotifiers( dccSock->check  );
}
示例#2
0
文件: dcc.c 项目: hiciu/ekg2
/*
 * gg_dcc_socket_open()
 */
int gg_dcc_socket_open(int port)
{
	if (gg_dcc_socket)
		return 0;

	if (!(gg_dcc_socket = gg_dcc_socket_create(1, port)))
		return -1;

	watch_add(&gg_plugin, gg_dcc_socket->fd, gg_dcc_socket->check, gg_dcc_handler_open, gg_dcc_socket);

	return 0;
}
示例#3
0
void __cdecl GGPROTO::dccmainthread(void*)
{
	uin_t uin;
	gg_event *e;
	struct timeval tv;
	fd_set rd, wd;
	int ret;
	SOCKET maxfd;
	DWORD tick;
	list_t l;
	char szFilename[MAX_PATH];

	// Zero up lists
	watches = transfers = requests = l = NULL;

	debugLogA("dccmainthread(): started. DCC Server Thread Starting");

	// Readup number
	if (!(uin = getDword(GG_KEY_UIN, 0)))
	{
		debugLogA("dccmainthread(): No Gadu-Gadu number specified. Exiting.");
		if (hEvent) SetEvent(hEvent);
#ifdef DEBUGMODE
		debugLogA("dccmainthread(): end 1.");
#endif
		return;
	}

	// Create listen socket on config direct port
	if (!(dcc = gg_dcc_socket_create(uin, (uint16_t)getWord(GG_KEY_DIRECTPORT, GG_KEYDEF_DIRECTPORT))))
	{
		debugLogA("dccmainthread(): Cannot create DCC listen socket. Exiting.");
		// Signalize mainthread we haven't start
		if (hEvent) SetEvent(hEvent);
#ifdef DEBUGMODE
		debugLogA("dccmainthread(): end 2.");
#endif
		return;
	}

	gg_dcc_port = dcc->port;
	gg_dcc_ip = inet_addr("255.255.255.255");
	debugLogA("dccmainthread(): Listening on port %d.", gg_dcc_port);

	// Signalize mainthread we started
	if (hEvent) SetEvent(hEvent);

	// Add main dcc handler to watches
	list_add(&watches, dcc, 0);

	// Do while we are in the main server thread
	while(pth_dcc.dwThreadId && dcc)
	{
		// Timeouts
		tv.tv_sec = 1;
		tv.tv_usec = 0;

		// Prepare descriptiors for select
		FD_ZERO(&rd);
		FD_ZERO(&wd);

		for (maxfd = 0, l = watches; l; l = l->next)
		{
			gg_common *w = (gg_common*)l->data;

			if (!w || w->state == GG_STATE_ERROR || w->state == GG_STATE_IDLE || w->state == GG_STATE_DONE)
				continue;

			// Check if it's proper descriptor
			if (w->fd == -1) continue;

			if (w->fd > maxfd)
				maxfd = w->fd;
			if ((w->check & GG_CHECK_READ))
				FD_SET(w->fd, &rd);
			if ((w->check & GG_CHECK_WRITE))
				FD_SET(w->fd, &wd);
		}

		// Wait for data on selects
		ret = select(maxfd + 1, &rd, &wd, NULL, &tv);

		// Check for select error
		if (ret == -1)
		{
			if (errno == EBADF)
				debugLogA("dccmainthread(): Bad descriptor on select().");
			else if (errno != EINTR)
				debugLogA("dccmainthread(): Unknown error on select().");
			continue;
		}

		// Process watches (carefull with l)
		l = watches;
		gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
		while (l)
		{
			struct gg_common *local_c = (gg_common*)l->data;
			struct gg_dcc *local_dcc = (gg_dcc*)l->data;
			struct gg_dcc7 *local_dcc7 = (gg_dcc7*)l->data;
			l = l->next;

			switch (local_c->type)
			{
				default:
					if (!local_dcc || (!FD_ISSET(local_dcc->fd, &rd) && !FD_ISSET(local_dcc->fd, &wd)))
						continue;

					/////////////////////////////////////////////////////////////////
					// Process DCC events

					// Connection broken/closed
					gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 2, "ft_mutex", 1);
					if (!(e = gg_dcc_socket_watch_fd(local_dcc)))
					{
						debugLogA("dccmainthread(): Socket closed.");
						// Remove socket and _close
						gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
						list_remove(&watches, local_dcc, 0);
						gg_dcc_socket_free(local_dcc);

						// Check if it's main socket
						if (local_dcc == dcc) dcc = NULL;
						continue;
					} else {
						gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
						debugLogA("dccmainthread(): Event: %s", ggdebug_eventtype(e));
					}

					switch(e->type)
					{
						// Client connected
						case GG_EVENT_DCC_NEW:
							list_add(&watches, e->event.dcc_new, 0);
							e->event.dcc_new = NULL;
							break;

						//
						case GG_EVENT_NONE:
							// If transfer in progress do status
							if (local_dcc->file_fd != -1 && local_dcc->offset > 0 && (((tick = GetTickCount()) - local_dcc->tick) > GGSTATREFRESHEVERY))
							{
								PROTOFILETRANSFERSTATUS pfts;
								local_dcc->tick = tick;
								mir_snprintf(szFilename, "%s%s", local_dcc->folder, local_dcc->file_info.filename);
								memset(&pfts, 0, sizeof(PROTOFILETRANSFERSTATUS));
								pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS);
								pfts.hContact = (UINT_PTR)local_dcc->contact;
								pfts.flags = (local_dcc->type == GG_SESSION_DCC_SEND);
								pfts.pszFiles = NULL;
								pfts.totalFiles = 1;
								pfts.currentFileNumber = 0;
								pfts.totalBytes = local_dcc->file_info.size;
								pfts.totalProgress = local_dcc->offset;
								pfts.szWorkingDir = local_dcc->folder;
								pfts.szCurrentFile = szFilename;
								pfts.currentFileSize = local_dcc->file_info.size;
								pfts.currentFileProgress = local_dcc->offset;
								pfts.currentFileTime = 0;
								gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 3, "ft_mutex", 1);
								ProtoBroadcastAck((UINT_PTR)local_dcc->contact, ACKTYPE_FILE, ACKRESULT_DATA, local_dcc, (LPARAM)&pfts);
								gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
							}
							break;

						// Connection was successfuly ended
						case GG_EVENT_DCC_DONE:
							debugLogA("dccmainthread(): Client: %d, Transfer done ! Closing connection.", dcc->peer_uin);
							// Remove from watches
							list_remove(&watches, local_dcc, 0);
							// Close file & success
							if (local_dcc->file_fd != -1)
							{
								PROTOFILETRANSFERSTATUS pfts;
								mir_snprintf(szFilename, "%s%s", local_dcc->folder, local_dcc->file_info.filename);
								memset(&pfts, 0, sizeof(PROTOFILETRANSFERSTATUS));
								pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS);
								pfts.hContact = (UINT_PTR)local_dcc->contact;
								pfts.flags = (local_dcc->type == GG_SESSION_DCC_SEND);
								pfts.pszFiles = NULL;
								pfts.totalFiles = 1;
								pfts.currentFileNumber = 0;
								pfts.totalBytes = local_dcc->file_info.size;
								pfts.totalProgress = local_dcc->file_info.size;
								pfts.szWorkingDir = local_dcc->folder;
								pfts.szCurrentFile = szFilename;
								pfts.currentFileSize = local_dcc->file_info.size;
								pfts.currentFileProgress = local_dcc->file_info.size;
								pfts.currentFileTime = 0;
								gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 4, "ft_mutex", 1);
								ProtoBroadcastAck((UINT_PTR)local_dcc->contact, ACKTYPE_FILE, ACKRESULT_DATA, local_dcc, (LPARAM)&pfts);
								gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
								_close(local_dcc->file_fd); local_dcc->file_fd = -1;
								gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 5, "ft_mutex", 1);
								ProtoBroadcastAck((UINT_PTR)local_dcc->contact, ACKTYPE_FILE, ACKRESULT_SUCCESS, local_dcc, 0);
								gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
							}
							// Free dcc
							gg_free_dcc(local_dcc); if (local_dcc == dcc) dcc = NULL;
							break;

						// Client error
						case GG_EVENT_DCC_ERROR:
							switch (e->event.dcc_error)
							{
								case GG_ERROR_DCC_HANDSHAKE:
									debugLogA("dccmainthread(): Client: %d, Handshake error.", local_dcc->peer_uin);
									break;
								case GG_ERROR_DCC_NET:
									debugLogA("dccmainthread(): Client: %d, Network error.", local_dcc->peer_uin);
									break;
								case GG_ERROR_DCC_FILE:
									debugLogA("dccmainthread(): Client: %d, File read/write error.", local_dcc->peer_uin);
									break;
								case GG_ERROR_DCC_EOF:
									debugLogA("dccmainthread(): Client: %d, End of file/connection error.", local_dcc->peer_uin);
									break;
								case GG_ERROR_DCC_REFUSED:
									debugLogA("dccmainthread(): Client: %d, Connection refused error.", local_dcc->peer_uin);
									break;
								default:
									debugLogA("dccmainthread(): Client: %d, Unknown error.", local_dcc->peer_uin);
							}
							// Don't do anything if it's main socket
							if (local_dcc == dcc) break;

							// Remove from watches
							list_remove(&watches, local_dcc, 0);

							// Close file & fail
							if (local_dcc->contact)
							{
								_close(local_dcc->file_fd); local_dcc->file_fd = -1;
								gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 6, "ft_mutex", 1);
								ProtoBroadcastAck((UINT_PTR)local_dcc->contact, ACKTYPE_FILE, ACKRESULT_FAILED, local_dcc, 0);
								gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
							}
							// Free dcc
							gg_free_dcc(local_dcc); if (local_dcc == dcc) dcc = NULL;
							break;

						// Need file acknowledgement
						case GG_EVENT_DCC_NEED_FILE_ACK:
							debugLogA("dccmainthread(): Client: %d, File ack filename \"%s\" size %d.", local_dcc->peer_uin,
									local_dcc->file_info.filename, local_dcc->file_info.size);
							// Do not watch for transfer until user accept it
							list_remove(&watches, local_dcc, 0);
							// Add to waiting transfers
							list_add(&transfers, local_dcc, 0);

							//////////////////////////////////////////////////
							// Add file recv request
							{
								// Make new ggtransfer struct
								local_dcc->contact = (void*)getcontact(local_dcc->peer_uin, 0, 0, NULL);
								TCHAR* filenameT = mir_utf8decodeT((char*)dcc->file_info.filename);

								PROTORECVFILET pre = {0};
								pre.dwFlags = PRFF_TCHAR;
								pre.fileCount = 1;
								pre.timestamp = time(NULL);
								pre.descr.t = filenameT;
								pre.files.t = &filenameT;
								pre.lParam = (LPARAM)local_dcc;

								gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 7, "ft_mutex", 1);
								ProtoChainRecvFile((UINT_PTR)local_dcc->contact, &pre);
								gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);

								mir_free(filenameT);
							}
							break;

						// Need client accept
						case GG_EVENT_DCC_CLIENT_ACCEPT:
							debugLogA("dccmainthread(): Client: %d, Client accept.", local_dcc->peer_uin);
							// Check if user is on the list and if it is my uin
							if (getcontact(local_dcc->peer_uin, 0, 0, NULL) &&
								getDword(GG_KEY_UIN, -1) == local_dcc->uin)
								break;

							// Kill unauthorized dcc
							list_remove(&watches, dcc, 0);
							gg_free_dcc(local_dcc); if (local_dcc == dcc) dcc = NULL;
							break;

						// Client connected as we wished to (callback)
						case GG_EVENT_DCC_CALLBACK:
						{
							int found = 0;
							debugLogA("dccmainthread(): Callback from client %d.", local_dcc->peer_uin);
							// Seek for stored callback request
							for (l = requests; l; l = l->next)
							{
								struct gg_dcc *req = (gg_dcc*)l->data;

								if (req && req->peer_uin == local_dcc->peer_uin)
								{
									gg_dcc_set_type(local_dcc, GG_SESSION_DCC_SEND);
									found = 1;

									// Copy data req ===> dcc
									local_dcc->folder = req->folder;
									local_dcc->contact = req->contact;
									local_dcc->file_fd = req->file_fd;
									memcpy(&local_dcc->file_info, &req->file_info, sizeof(struct gg_file_info));
									// Copy data back to dcc ===> req
									memcpy(req, local_dcc, sizeof(struct gg_dcc));

									// Remove request
									list_remove(&requests, req, 0);
									// Remove dcc from watches
									list_remove(&watches, local_dcc, 0);
									// Add request to watches
									list_add(&watches, req, 0);
									// Free old dat
									gg_free_dcc(local_dcc);
									debugLogA("dccmainthread(): Found stored request to client %d, filename \"%s\" size %d, folder \"%s\".",
										req->peer_uin, req->file_info.filename, req->file_info.size, req->folder);
									break;
								}
							}

							if (!found)
							{
								debugLogA("dccmainthread(): Unknown request to client %d.", local_dcc->peer_uin);
								// Kill unauthorized dcc
								list_remove(&watches, local_dcc, 0);
								gg_free_dcc(local_dcc); if (local_dcc == dcc) dcc = NULL;
							}
							break;
						}
					}

					// Free event
					gg_free_event(e);
					break;

				case GG_SESSION_DCC7_SOCKET:
				case GG_SESSION_DCC7_GET:
				case GG_SESSION_DCC7_SEND:
				case GG_SESSION_DCC7_VOICE:
					if (!local_dcc7 || (!FD_ISSET(local_dcc7->fd, &rd) && !FD_ISSET(local_dcc7->fd, &wd)))
						continue;

					/////////////////////////////////////////////////////////////////
					// Process DCC7 events

					// Connection broken/closed
					gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 8, "ft_mutex", 1);
					if (!(e = gg_dcc7_watch_fd(local_dcc7)))
					{
						debugLogA("dccmainthread(): Socket closed.");
						// Remove socket and _close
						gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
						list_remove(&watches, local_dcc7, 0);
						gg_dcc7_free(local_dcc7);
						continue;
					} else {
						gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
						debugLogA("dccmainthread(): Event: %s", ggdebug_eventtype(e));
					}

					switch(e->type)
					{
						//
						case GG_EVENT_NONE:
							// If transfer in progress do status
							if (local_dcc7->file_fd != -1 && local_dcc7->offset > 0 && (((tick = GetTickCount()) - local_dcc7->tick) > GGSTATREFRESHEVERY))
							{
								PROTOFILETRANSFERSTATUS pfts;
								local_dcc7->tick = tick;
								mir_snprintf(szFilename, "%s%s", local_dcc->folder, local_dcc7->filename);
								memset(&pfts, 0, sizeof(PROTOFILETRANSFERSTATUS));
								pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS);
								pfts.hContact = (UINT_PTR)local_dcc7->contact;
								pfts.flags = (local_dcc7->type == GG_SESSION_DCC7_SEND);
								pfts.pszFiles = NULL;
								pfts.totalFiles = 1;
								pfts.currentFileNumber = 0;
								pfts.totalBytes = local_dcc7->size;
								pfts.totalProgress = local_dcc7->offset;
								pfts.szWorkingDir = local_dcc7->folder;
								pfts.szCurrentFile = szFilename;
								pfts.currentFileSize = local_dcc7->size;
								pfts.currentFileProgress = local_dcc7->offset;
								pfts.currentFileTime = 0;
								gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 9, "ft_mutex", 1);
								ProtoBroadcastAck((UINT_PTR)local_dcc7->contact, ACKTYPE_FILE, ACKRESULT_DATA, local_dcc7, (LPARAM)&pfts);
								gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
							}
							break;

						// Connection was successfuly ended
						case GG_EVENT_DCC7_DONE:
							debugLogA("dccmainthread(): Client: %d, Transfer done ! Closing connection.", dcc->peer_uin);
							// Remove from watches
							list_remove(&watches, local_dcc7, 0);
							// Close file & success
							if (local_dcc7->file_fd != -1)
							{
								PROTOFILETRANSFERSTATUS pfts;
								mir_snprintf(szFilename, "%s%s", local_dcc->folder, local_dcc7->filename);
								memset(&pfts, 0, sizeof(PROTOFILETRANSFERSTATUS));
								pfts.cbSize = sizeof(PROTOFILETRANSFERSTATUS);
								pfts.hContact = (UINT_PTR)local_dcc7->contact;
								pfts.flags = (local_dcc7->type == GG_SESSION_DCC7_SEND);
								pfts.pszFiles = NULL;
								pfts.totalFiles = 1;
								pfts.currentFileNumber = 0;
								pfts.totalBytes = local_dcc7->size;
								pfts.totalProgress = local_dcc7->size;
								pfts.szWorkingDir = local_dcc7->folder;
								pfts.szCurrentFile = szFilename;
								pfts.currentFileSize = local_dcc7->size;
								pfts.currentFileProgress = local_dcc7->size;
								pfts.currentFileTime = 0;
								gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 10, "ft_mutex", 1);
								ProtoBroadcastAck((UINT_PTR)local_dcc7->contact, ACKTYPE_FILE, ACKRESULT_DATA, local_dcc7, (LPARAM)&pfts);
								gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
								_close(local_dcc7->file_fd); local_dcc7->file_fd = -1;
								gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 11, "ft_mutex", 1);
								ProtoBroadcastAck((UINT_PTR)local_dcc7->contact, ACKTYPE_FILE, ACKRESULT_SUCCESS, local_dcc7, 0);
								gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
							}
							// Free dcc
							gg_dcc7_free(local_dcc7);
							break;

						// Client error
						case GG_EVENT_DCC7_ERROR:
							switch (e->event.dcc7_error)
							{
								case GG_ERROR_DCC7_HANDSHAKE:
									debugLogA("dccmainthread(): Client: %d, Handshake error.", local_dcc7->peer_uin);
									break;
								case GG_ERROR_DCC7_NET:
									debugLogA("dccmainthread(): Client: %d, Network error.", local_dcc7->peer_uin);
									break;
								case GG_ERROR_DCC7_FILE:
									debugLogA("dccmainthread(): Client: %d, File read/write error.", local_dcc7->peer_uin);
									break;
								case GG_ERROR_DCC7_EOF:
									debugLogA("dccmainthread(): Client: %d, End of file/connection error.", local_dcc7->peer_uin);
									break;
								case GG_ERROR_DCC7_REFUSED:
									debugLogA("dccmainthread(): Client: %d, Connection refused error.", local_dcc7->peer_uin);
									break;
								case GG_ERROR_DCC7_RELAY:
									debugLogA("dccmainthread(): Client: %d, Relay connection error.", local_dcc7->peer_uin);
									break;
								default:
									debugLogA("dccmainthread(): Client: %d, Unknown error.", local_dcc7->peer_uin);
							}
							// Remove from watches
							list_remove(&watches, local_dcc7, 0);

							// Close file & fail
							if (local_dcc7->file_fd != -1)
							{
								_close(local_dcc7->file_fd);
								local_dcc7->file_fd = -1;
							}

							if (local_dcc7->contact) {
								gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 12, "ft_mutex", 1);
								ProtoBroadcastAck((UINT_PTR)local_dcc7->contact, ACKTYPE_FILE, ACKRESULT_FAILED, local_dcc7, 0);
								gg_EnterCriticalSection(&ft_mutex, "dccmainthread", 37, "ft_mutex", 1);
							}

							// Free dcc
							gg_dcc7_free(local_dcc7);
							break;
					}

					// Free event
					gg_free_event(e);
					break;
			}
		}
		gg_LeaveCriticalSection(&ft_mutex, "dccmainthread", 37, 1, "ft_mutex", 1);
	}

	// Close all dcc client sockets
	for (l = watches; l; l = l->next)
	{
		struct gg_common *c = (gg_common*)l->data;
		if (!c) continue;
		if (c->type == GG_SESSION_DCC7_SOCKET || c->type == GG_SESSION_DCC7_SEND || c->type == GG_SESSION_DCC7_GET)
		{
			struct gg_dcc7 *local_dcc7 = (gg_dcc7*)l->data;
			gg_dcc7_free(local_dcc7);
		}
		else
		{
			struct gg_dcc *local_dcc = (gg_dcc*)l->data;
			gg_dcc_socket_free(local_dcc);

			// Check if it's main socket
			if (local_dcc == dcc) dcc = NULL;
		}
	}
	// Close all waiting for aknowledgle transfers
	for (l = transfers; l; l = l->next)
	{
		struct gg_common *c = (gg_common*)l->data;
		if (!c) continue;
		if (c->type == GG_SESSION_DCC7_SOCKET || c->type == GG_SESSION_DCC7_SEND || c->type == GG_SESSION_DCC7_GET)
		{
			struct gg_dcc7 *local_dcc7 = (gg_dcc7*)l->data;
			gg_dcc7_free(local_dcc7);
		}
		else
		{
			struct gg_dcc *local_dcc = (gg_dcc*)l->data;
			gg_dcc_socket_free(local_dcc);
		}
	}
	// Close all waiting dcc requests
	for (l = requests; l; l = l->next)
	{
		struct gg_dcc *local_dcc = (gg_dcc*)l->data;
		if (local_dcc) gg_free_dcc(local_dcc);
	}
	list_destroy(watches, 0);
	list_destroy(transfers, 0);
	list_destroy(requests, 0);

	gg_dcc_port = 0;
	gg_dcc_ip = 0;
	debugLogA("dccmainthread(): end. DCC Server Thread Ending");
}