コード例 #1
0
void
EventDispatcher::_SendFakeMouseMoved(BMessage* message)
{
	BMessenger target;
	int32 viewToken;
	if (message->FindInt32("view_token", &viewToken) != B_OK
		|| message->FindMessenger("target", &target) != B_OK)
		return;

	if (fDesktop == NULL)
		return;

	// Check if the target is still valid
	::EventTarget* eventTarget = NULL;

	fDesktop->LockSingleWindow();

	if (target.IsValid())
		eventTarget = fDesktop->FindTarget(target);

	fDesktop->UnlockSingleWindow();

	if (eventTarget == NULL)
		return;

	BMessage moved(B_MOUSE_MOVED);
	moved.AddPoint("screen_where", fLastCursorPosition);
	moved.AddInt32("buttons", fLastButtons);

	if (fDraggingMessage)
		moved.AddMessage("be:drag_message", &fDragMessage);

	if (fPreviousMouseTarget != NULL
		&& fPreviousMouseTarget->Messenger() != target) {
		_AddTokens(&moved, fPreviousMouseTarget, B_POINTER_EVENTS);
		_SendMessage(fPreviousMouseTarget->Messenger(), &moved,
			kMouseTransitImportance);

		_RemoveTokens(&moved);
	}

	moved.AddInt32("_view_token", viewToken);
		// this only belongs to the new target

	moved.AddBool("be:transit_only", true);
		// let the view know this what not user generated

	_SendMessage(target, &moved, kMouseTransitImportance);

	fPreviousMouseTarget = eventTarget;
}
コード例 #2
0
ファイル: script_debugger.cpp プロジェクト: 2asoft/xray
void CScriptDebugger::DrawCurrentState()
{
	m_lua->DrawStackTrace();
	m_callStack->SetStackTraceLevel(0);
	m_lua->DrawGlobalVariables();
	_SendMessage(DMSG_GOTO_STACKTRACE_LEVEL, GetStackTraceLevel(), 0);
}
コード例 #3
0
void
EventDispatcher::_DeliverDragMessage()
{
	ETRACE(("EventDispatcher::_DeliverDragMessage()\n"));

	if (fDraggingMessage && fPreviousMouseTarget != NULL) {
		BMessage::Private(fDragMessage).SetWasDropped(true);
		fDragMessage.RemoveName("_original_what");
		fDragMessage.AddInt32("_original_what", fDragMessage.what);
		fDragMessage.AddPoint("_drop_point_", fLastCursorPosition);
		fDragMessage.AddPoint("_drop_offset_", fDragOffset);
		fDragMessage.what = _MESSAGE_DROPPED_;

		_SendMessage(fPreviousMouseTarget->Messenger(),
			&fDragMessage, 100.0);
	}

	fDragMessage.MakeEmpty();
	fDragMessage.what = 0;
	fDraggingMessage = false;

	fHWInterface->SetDragBitmap(NULL, B_ORIGIN);
	if (fDragBitmap != NULL) {
		fDragBitmap->ReleaseReference();
		fDragBitmap = NULL;
	}
}
コード例 #4
0
ファイル: script_debugger.cpp プロジェクト: 2asoft/xray
void CScriptDebugger::AddGlobalVariable(const char *name, const char *type, const char *value)
{
	Variable var;
	strcat(var.szName, name );
	strcat(var.szType, type );
	strcat(var.szValue, value );
	_SendMessage(DMSG_ADD_GLOBALVARIABLE, (WPARAM)&var, 0);
}
コード例 #5
0
ファイル: script_debugger.cpp プロジェクト: 2asoft/xray
void CScriptDebugger::AddStackTrace(const char* szDesc, const char* szFile, int nLine)
{
	StackTrace st;
	strcat(st.szDesc, szDesc);
	strcat(st.szFile, szFile);
	st.nLine = nLine;
	_SendMessage(DMSG_ADD_STACKTRACE, (WPARAM)&st, 0);
}
コード例 #6
0
void
BUrlProtocolDispatchingListener::RequestCompleted(BUrlRequest* caller,
	bool success)
{
	BMessage message(B_URL_PROTOCOL_NOTIFICATION);
	message.AddBool("url:success", success);
	
	_SendMessage(&message, B_URL_PROTOCOL_REQUEST_COMPLETED, caller);
}
コード例 #7
0
void
BUrlProtocolDispatchingListener::DataReceived(BUrlProtocol* caller, 
	const char* data, ssize_t size)
{
	BMessage message(B_URL_PROTOCOL_NOTIFICATION);
	message.AddData("url:data", B_STRING_TYPE, data, size, true, 1);
	
	_SendMessage(&message, B_URL_PROTOCOL_DATA_RECEIVED, caller);
}
コード例 #8
0
void
BUrlProtocolDispatchingListener::HostnameResolved(BUrlRequest* caller,
	const char* ip)
{
	BMessage message(B_URL_PROTOCOL_NOTIFICATION);
	message.AddString("url:hostIp", ip);
	
	_SendMessage(&message, B_URL_PROTOCOL_HOSTNAME_RESOLVED, caller);
}
コード例 #9
0
void
BUrlProtocolDispatchingListener::DownloadProgress(BUrlProtocol* caller, 
	ssize_t bytesReceived, ssize_t bytesTotal)
{
	BMessage message(B_URL_PROTOCOL_NOTIFICATION);
	message.AddInt32("url:bytesReceived", bytesReceived);
	message.AddInt32("url:bytesTotal", bytesTotal);
	
	_SendMessage(&message, B_URL_PROTOCOL_DOWNLOAD_PROGRESS, caller);
}
コード例 #10
0
ファイル: MSN.cpp プロジェクト: ModeenF/Caya
void
MSNP::_NotifyProgress(const char* title, const char* message, float progress)
{
	BMessage msg(IM_MESSAGE);
	msg.AddInt32("im_what", IM_PROGRESS);
	msg.AddString("title", title);
	msg.AddString("message", message);
	msg.AddFloat("progress", progress);
	_SendMessage(&msg);
}
コード例 #11
0
void
BUrlProtocolDispatchingListener::DebugMessage(BUrlRequest* caller,
	BUrlProtocolDebugMessage type, const char* text)
{
	BMessage message(B_URL_PROTOCOL_NOTIFICATION);
	message.AddInt32("url:type", type);
	message.AddString("url:text", text);

	_SendMessage(&message, B_URL_PROTOCOL_DEBUG_MESSAGE, caller);
}
コード例 #12
0
void
BUrlProtocolDispatchingListener::UploadProgress(BUrlRequest* caller,
	ssize_t bytesSent, ssize_t bytesTotal)
{
	BMessage message(B_URL_PROTOCOL_NOTIFICATION);
	message.AddInt32("url:bytesSent", bytesSent);
	message.AddInt32("url:bytesTotal", bytesTotal);
	
	_SendMessage(&message, B_URL_PROTOCOL_UPLOAD_PROGRESS, caller);
}
コード例 #13
0
ファイル: MSN.cpp プロジェクト: ModeenF/Caya
void
MSNP::_Notify(notification_type type, const char* title, const char* message)
{
	BMessage msg(IM_MESSAGE);
	msg.AddInt32("im_what", IM_NOTIFICATION);
	msg.AddInt32("type", (int32)type);
	msg.AddString("title", title);
	msg.AddString("message", message);
	_SendMessage(&msg);
}
コード例 #14
0
void
ReplaceWindow::MessageReceived(BMessage* msg)
{
	switch (msg->what) {
		case MSG_REPLACE:
			_SendMessage(MSG_REPLACE);
			break;
		case CHANGE_WINDOW:
			_ChangeUI();
			break;
		case MSG_REPLACE_ALL:
			_SendMessage(MSG_REPLACE_ALL);
			break;

		default:
			BWindow::MessageReceived(msg);
			break;
	}
}
コード例 #15
0
ファイル: script_debugger.cpp プロジェクト: 2asoft/xray
CScriptDebugger::~CScriptDebugger()
{
	if (Active())
		_SendMessage	(DMSG_CLOSE_CONNECTION,0,0);

	CloseHandle			(m_mailSlot);

	xr_delete			(m_threads);
	xr_delete			(m_callStack);
	xr_delete			(m_lua);
}
コード例 #16
0
ファイル: script_debugger.cpp プロジェクト: 2asoft/xray
void CScriptDebugger::DebugBreak(const char *szFile, int nLine)
{
	m_nMode = DMOD_NONE;

	m_threads->Fill();
	m_threads->DrawThreads();

	DrawCurrentState();

	_SendMessage(DMSG_DEBUG_BREAK, 0, 0);
}
コード例 #17
0
ファイル: MSN.cpp プロジェクト: ModeenF/Caya
void
MSNP::Error(const char* message, const char* who)
{
	BMessage msg(IM_ERROR);
	msg.AddString("protocol", kProtocolSignature);
	if (who)
		msg.AddString("id", who);
	msg.AddString("error", message);

	_SendMessage(&msg);
}
コード例 #18
0
void
BUrlProtocolDispatchingListener::DataReceived(BUrlRequest* caller,
	const char* data, off_t position, ssize_t size)
{
	BMessage message(B_URL_PROTOCOL_NOTIFICATION);
	status_t result = message.AddData("url:data", B_STRING_TYPE, data, size,
		true, 1);
	assert(result == B_OK);

	result = message.AddInt32("url:position", position);
	assert(result == B_OK);
	
	_SendMessage(&message, B_URL_PROTOCOL_DATA_RECEIVED, caller);
}
コード例 #19
0
void
BUrlProtocolDispatchingListener::HeadersReceived(BUrlRequest* caller,
	const BUrlResult& result)
{
	/* The URL request does not keep the headers valid after calling this
	 * method. For asynchronous delivery to work, we need to archive them
	 * into the message. */
	BMessage message(B_URL_PROTOCOL_NOTIFICATION);
	BMessage archive;
	result.Archive(&archive, true);
	message.AddMessage("url:result", &archive);

	_SendMessage(&message, B_URL_PROTOCOL_HEADERS_RECEIVED, caller);
}
コード例 #20
0
ファイル: script_debugger.cpp プロジェクト: 2asoft/xray
void CScriptDebugger::Connect(LPCSTR mslot_name)
{
	m_bIdePresent = CheckExisting(IDE_MAIL_SLOT);
	ZeroMemory(m_curr_connected_mslot,sizeof(m_curr_connected_mslot));
	if (Active())
	{
		_SendMessage(DMSG_NEW_CONNECTION,0,0);
		CMailSlotMsg msg;
		msg.w_int(DMSG_GET_BREAKPOINTS);
		SendMessageToIde(msg);
		WaitForReply(false);
		strcat(m_curr_connected_mslot,mslot_name);
	}
}
コード例 #21
0
ファイル: DHCPClient.cpp プロジェクト: mmanley/Antares
DHCPClient::~DHCPClient()
{
	if (fStatus != B_OK)
		return;

	delete fRunner;

	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
	if (socket < 0)
		return;

	// release lease

	dhcp_message release(DHCP_RELEASE);
	_PrepareMessage(release, BOUND);

	_SendMessage(socket, release, fServer);
	close(socket);

	closelog_thread();
}
コード例 #22
0
e_status_t
EMessenger::SendMessage(const EMessage *a_message, EMessage *reply_message, e_bigtime_t sendTimeout, e_bigtime_t replyTimeout) const
{
	if(a_message == NULL || reply_message == NULL)
	{
		ETK_WARNING("[APP]: %s --- Can't post empty message or \"reply_message\" assigned to be \"NULL\".", __PRETTY_FUNCTION__);
		return E_BAD_VALUE;
	}

	void *port = etk_create_port(1, NULL, ETK_AREA_ACCESS_OWNER);
	if(port == NULL) return E_NO_MORE_PORTS;

	EMessage *aMsg = new EMessage(*a_message);
	if(aMsg->fSource != NULL) etk_delete_port(aMsg->fSource);
	aMsg->fTeam = etk_get_current_team_id();
	aMsg->fIsReply = false;
	aMsg->fReplyToken = E_MAXUINT64;
	aMsg->fReplyTokenTimestamp = E_MAXINT64;
	aMsg->fNoticeSource = true; // auto close the port when deleted
	aMsg->fSource = port; // auto delete the port when deleted

	e_status_t status = _SendMessage(aMsg, E_MAXUINT64, sendTimeout);
	if(status == E_OK)
	{
		EMessage *reply = _GetMessageFromPort(port, E_TIMEOUT, replyTimeout, &status);
		if(reply != NULL)
		{
			*reply_message = *reply;
			delete reply;
		}
		else
		{
			reply_message->what = E_NO_REPLY;
		}
	}

	delete aMsg;
	return status;
}
コード例 #23
0
e_status_t
EMessenger::SendMessage(const EMessage *a_message,
			EHandler *reply_to,
			e_bigtime_t timeout) const
{
	if(a_message == NULL)
	{
		ETK_WARNING("[APP]: %s --- Can't post empty message.", __PRETTY_FUNCTION__);
		return E_BAD_VALUE;
	}

	euint64 replyToken = etk_get_handler_token(reply_to);

	EMessage aMsg(*a_message);
	aMsg.fIsReply = false;
	if(aMsg.fSource != NULL)
	{
		etk_delete_port(aMsg.fSource);
		aMsg.fSource = NULL;
	}

	return _SendMessage(&aMsg, replyToken, timeout);
}
コード例 #24
0
	void _AddTargets(ListenerList* listenerList, uint32 flags,
		messaging_target* targets, int32& targetCount, int32 object,
		uint32 opcode)
	{
		if (listenerList == NULL)
			return;

		for (ListenerList::List::Iterator it
				= listenerList->listeners.GetIterator();
			Listener* listener = it.Next();) {
			if ((listener->flags & flags) == 0)
				continue;

			// array is full -- need to flush it first
			if (targetCount == kMaxMessagingTargetCount) {
				_SendMessage(targets, targetCount, object, opcode);
				targetCount = 0;
			}

			// add the listener
			targets[targetCount].port = listener->port;
			targets[targetCount++].token = listener->token;
		}
	}
コード例 #25
0
void
BUrlProtocolDispatchingListener::HeadersReceived(BUrlProtocol* caller)
{
	BMessage message(B_URL_PROTOCOL_NOTIFICATION);
	_SendMessage(&message, B_URL_PROTOCOL_HEADERS_RECEIVED, caller);
}
コード例 #26
0
void
BUrlProtocolDispatchingListener::ConnectionOpened(BUrlRequest* caller)
{
	BMessage message(B_URL_PROTOCOL_NOTIFICATION);
	_SendMessage(&message, B_URL_PROTOCOL_CONNECTION_OPENED, caller);
}
コード例 #27
0
void
BUrlProtocolDispatchingListener::ResponseStarted(BUrlRequest* caller)
{
	BMessage message(B_URL_PROTOCOL_NOTIFICATION);
	_SendMessage(&message, B_URL_PROTOCOL_RESPONSE_STARTED, caller);
}
コード例 #28
0
	virtual void EventOccurred(NotificationService& service,
		const KMessage* event)
	{
		MutexLocker locker(fLock);

		int32 eventCode;
		int32 teamID;
		if (event->FindInt32("event", &eventCode) != B_OK
			|| event->FindInt32("team", &teamID) != B_OK) {
			return;
		}

		int32 object;
		uint32 opcode;
		uint32 flags;

		// translate the event
		if (event->What() == TEAM_MONITOR) {
			switch (eventCode) {
				case TEAM_ADDED:
					opcode = B_TEAM_CREATED;
					flags = B_WATCH_SYSTEM_TEAM_CREATION;
					break;
				case TEAM_REMOVED:
					opcode = B_TEAM_DELETED;
					flags = B_WATCH_SYSTEM_TEAM_DELETION;
					break;
				case TEAM_EXEC:
					opcode = B_TEAM_EXEC;
					flags = B_WATCH_SYSTEM_TEAM_CREATION
						| B_WATCH_SYSTEM_TEAM_DELETION;
					break;
				default:
					return;
			}

			object = teamID;
		} else if (event->What() == THREAD_MONITOR) {
			if (event->FindInt32("thread", &object) != B_OK)
				return;

			switch (eventCode) {
				case THREAD_ADDED:
					opcode = B_THREAD_CREATED;
					flags = B_WATCH_SYSTEM_THREAD_CREATION;
					break;
				case THREAD_REMOVED:
					opcode = B_THREAD_DELETED;
					flags = B_WATCH_SYSTEM_THREAD_DELETION;
					break;
				case THREAD_NAME_CHANGED:
					opcode = B_THREAD_NAME_CHANGED;
					flags = B_WATCH_SYSTEM_THREAD_PROPERTIES;
					break;
				default:
					return;
			}
		} else
			return;

		// find matching listeners
		messaging_target targets[kMaxMessagingTargetCount];
		int32 targetCount = 0;

		_AddTargets(fTeamListeners.Lookup(teamID), flags, targets,
			targetCount, object, opcode);
		_AddTargets(fTeamListeners.Lookup(-1), flags, targets, targetCount,
			object, opcode);

		// send the message
		if (targetCount > 0)
			_SendMessage(targets, targetCount, object, opcode);
	}
コード例 #29
0
void
EventDispatcher::_EventLoop()
{
	BMessage* event;
	while (fStream->GetNextEvent(&event)) {
		BAutolock _(this);
		fLastUpdate = system_time();

		EventTarget* current = NULL;
		EventTarget* previous = NULL;
		bool pointerEvent = false;
		bool keyboardEvent = false;
		bool addedTokens = false;

		switch (event->what) {
			case kFakeMouseMoved:
				_SendFakeMouseMoved(event);
				break;
			case B_MOUSE_MOVED:
			{
				BPoint where;
				if (event->FindPoint("where", &where) == B_OK)
					fLastCursorPosition = where;

				if (fDraggingMessage)
					event->AddMessage("be:drag_message", &fDragMessage);

				if (!HasCursorThread()) {
					// There is no cursor thread, we need to move the cursor
					// ourselves
					BAutolock _(fCursorLock);

					if (fHWInterface != NULL) {
						fHWInterface->MoveCursorTo(fLastCursorPosition.x,
							fLastCursorPosition.y);
					}
				}

				// This is for B_NO_POINTER_HISTORY - we always want the
				// latest mouse moved event in the queue only
				if (fNextLatestMouseMoved == NULL)
					fNextLatestMouseMoved = fStream->PeekLatestMouseMoved();
				else if (fNextLatestMouseMoved != event) {
					// Drop older mouse moved messages if the server is lagging
					// too much (if the message is older than 100 msecs)
					bigtime_t eventTime;
					if (event->FindInt64("when", &eventTime) == B_OK) {
						if (system_time() - eventTime > 100000)
							break;
					}
				}

				// supposed to fall through
			}
			case B_MOUSE_DOWN:
			case B_MOUSE_UP:
			{
#ifdef TRACE_EVENTS
				if (event->what != B_MOUSE_MOVED)
					printf("mouse up/down event, previous target = %p\n", fPreviousMouseTarget);
#endif
				pointerEvent = true;

				if (fMouseFilter == NULL)
					break;

				EventTarget* mouseTarget = fPreviousMouseTarget;
				int32 viewToken = B_NULL_TOKEN;
				if (fMouseFilter->Filter(event, &mouseTarget, &viewToken,
						fNextLatestMouseMoved) == B_SKIP_MESSAGE) {
					// this is a work-around if the wrong B_MOUSE_UP
					// event is filtered out
					if (event->what == B_MOUSE_UP
						&& event->FindInt32("buttons") == 0) {
						fSuspendFocus = false;
						_RemoveTemporaryListeners();
					}
					break;
				}

				int32 buttons;
				if (event->FindInt32("buttons", &buttons) == B_OK)
					fLastButtons = buttons;
				else
					fLastButtons = 0;

				// The "where" field will be filled in by the receiver
				// (it's supposed to be expressed in local window coordinates)
				event->RemoveName("where");
				event->AddPoint("screen_where", fLastCursorPosition);

				if (event->what == B_MOUSE_MOVED
					&& fPreviousMouseTarget != NULL
					&& mouseTarget != fPreviousMouseTarget) {
					// Target has changed, we need to notify the previous target
					// that the mouse has exited its views
					addedTokens = _AddTokens(event, fPreviousMouseTarget,
						B_POINTER_EVENTS);
					if (addedTokens)
						_SetFeedFocus(event);

					_SendMessage(fPreviousMouseTarget->Messenger(), event,
						kMouseTransitImportance);
					previous = fPreviousMouseTarget;
				}

				current = fPreviousMouseTarget = mouseTarget;

				if (current != NULL) {
					int32 focusView = viewToken;
					addedTokens |= _AddTokens(event, current, B_POINTER_EVENTS,
						fNextLatestMouseMoved, &focusView);

					bool noPointerHistoryFocus = focusView != viewToken;

					if (viewToken != B_NULL_TOKEN)
						event->AddInt32("_view_token", viewToken);

					if (addedTokens && !noPointerHistoryFocus)
						_SetFeedFocus(event);
					else if (noPointerHistoryFocus) {
						// No tokens were added or the focus shouldn't get a
						// mouse moved
						break;
					}

					_SendMessage(current->Messenger(), event,
						event->what == B_MOUSE_MOVED
							? kMouseMovedImportance : kStandardImportance);
				}
				break;
			}

			case B_KEY_DOWN:
			case B_KEY_UP:
			case B_UNMAPPED_KEY_DOWN:
			case B_UNMAPPED_KEY_UP:
			case B_MODIFIERS_CHANGED:
			case B_INPUT_METHOD_EVENT:
				ETRACE(("key event, focus = %p\n", fFocus));

				if (fKeyboardFilter != NULL
					&& fKeyboardFilter->Filter(event, &fFocus) == B_SKIP_MESSAGE)
					break;

				keyboardEvent = true;

				if (fFocus != NULL && _AddTokens(event, fFocus,
						B_KEYBOARD_EVENTS)) {
					// if tokens were added, we need to explicetly suspend
					// focus in the event - if not, the event is simply not
					// forwarded to the target
					addedTokens = true;

					if (!fSuspendFocus)
						_SetFeedFocus(event);
				}

				// supposed to fall through

			default:
				// TODO: the keyboard filter sets the focus - ie. no other
				//	focus messages that go through the event dispatcher can
				//	go through.
				if (event->what == B_MOUSE_WHEEL_CHANGED)
					current = fPreviousMouseTarget;
				else
					current = fFocus;

				if (current != NULL && (!fSuspendFocus || addedTokens)) {
					_SendMessage(current->Messenger(), event,
						kStandardImportance);
				}
				break;
		}

		if (keyboardEvent || pointerEvent) {
			// send the event to the additional listeners

			if (addedTokens) {
				_RemoveTokens(event);
				_UnsetFeedFocus(event);
			}
			if (pointerEvent) {
				// this is added in the Desktop mouse processing
				// but it's only intended for the focus view
				event->RemoveName("_view_token");
			}

			for (int32 i = fTargets.CountItems(); i-- > 0;) {
				EventTarget* target = fTargets.ItemAt(i);

				// We already sent the event to the all focus and last focus
				// tokens
				if (current == target || previous == target)
					continue;

				// Don't send the message if there are no tokens for this event
				if (!_AddTokens(event, target,
						keyboardEvent ? B_KEYBOARD_EVENTS : B_POINTER_EVENTS,
						event->what == B_MOUSE_MOVED
							? fNextLatestMouseMoved : NULL))
					continue;

				if (!_SendMessage(target->Messenger(), event,
						event->what == B_MOUSE_MOVED
							? kMouseMovedImportance : kListenerImportance)) {
					// the target doesn't seem to exist anymore, let's remove it
					fTargets.RemoveItemAt(i);
				}
			}

			if (event->what == B_MOUSE_UP && fLastButtons == 0) {
				// no buttons are pressed anymore
				fSuspendFocus = false;
				_RemoveTemporaryListeners();
				if (fDraggingMessage)
					_DeliverDragMessage();
			}
		}

		if (fNextLatestMouseMoved == event)
			fNextLatestMouseMoved = NULL;
		delete event;
	}

	// The loop quit, therefore no more events are coming from the input
	// server, it must have died. Unset ourselves and notify the desktop.
	fThread = -1;
		// Needed to avoid problems with wait_for_thread in _Unset()
	_Unset();

	if (fDesktop)
		fDesktop->PostMessage(AS_EVENT_STREAM_CLOSED);
}
コード例 #30
0
ファイル: DHCPClient.cpp プロジェクト: mmanley/Antares
status_t
DHCPClient::_Negotiate(dhcp_state state)
{
	int socket = ::socket(AF_INET, SOCK_DGRAM, 0);
	if (socket < 0)
		return errno;

	sockaddr_in local;
	memset(&local, 0, sizeof(struct sockaddr_in));
	local.sin_family = AF_INET;
	local.sin_len = sizeof(struct sockaddr_in);
	local.sin_port = htons(DHCP_CLIENT_PORT);
	local.sin_addr.s_addr = INADDR_ANY;

	// Enable reusing the port . This is needed in case there is more
	// than 1 interface that needs to be configured. Note that the only reason
	// this works is because there is code below to bind to a specific
	// interface.
	int option = 1;
	setsockopt(socket, SOL_SOCKET, SO_REUSEPORT, &option, sizeof(option));

	if (bind(socket, (struct sockaddr *)&local, sizeof(local)) < 0) {
		close(socket);
		return errno;
	}

	sockaddr_in broadcast;
	memset(&broadcast, 0, sizeof(struct sockaddr_in));
	broadcast.sin_family = AF_INET;
	broadcast.sin_len = sizeof(struct sockaddr_in);
	broadcast.sin_port = htons(DHCP_SERVER_PORT);
	broadcast.sin_addr.s_addr = INADDR_BROADCAST;

	option = 1;
	setsockopt(socket, SOL_SOCKET, SO_BROADCAST, &option, sizeof(option));

	if (state == INIT) {
		// The local interface does not have an address yet, bind the socket
		// to the device directly.
		int linkSocket = ::socket(AF_LINK, SOCK_DGRAM, 0);
		if (linkSocket >= 0) {
			// we need to know the index of the device to be able to bind to it
			ifreq request;
			prepare_request(request, Device());
			if (ioctl(linkSocket, SIOCGIFINDEX, &request, sizeof(struct ifreq))
					== 0) {
				setsockopt(socket, SOL_SOCKET, SO_BINDTODEVICE,
					&request.ifr_index, sizeof(int));
			}

			close(linkSocket);
		}
	}

	bigtime_t previousLeaseTime = fLeaseTime;
	fLeaseTime = 0;
	fRenewalTime = 0;
	fRebindingTime = 0;

	status_t status = B_ERROR;
	time_t timeout;
	uint32 tries;
	_ResetTimeout(socket, timeout, tries);

	dhcp_message discover(DHCP_DISCOVER);
	_PrepareMessage(discover, state);

	dhcp_message request(DHCP_REQUEST);
	_PrepareMessage(request, state);

	// send discover/request message
	_SendMessage(socket, state == INIT ? discover : request,
		state != RENEWAL ? broadcast : fServer);
		// no need to check the status; in case of an error we'll just send
		// the message again

	// receive loop until we've got an offer and acknowledged it

	while (state != ACKNOWLEDGED) {
		char buffer[2048];
		ssize_t bytesReceived = recvfrom(socket, buffer, sizeof(buffer),
			0, NULL, NULL);
		if (bytesReceived < 0 && errno == B_TIMED_OUT) {
			// depending on the state, we'll just try again
			if (!_TimeoutShift(socket, timeout, tries)) {
				close(socket);
				return B_TIMED_OUT;
			}

			if (state == INIT)
				_SendMessage(socket, discover, broadcast);
			else {
				_SendMessage(socket, request,
					state != RENEWAL ? broadcast : fServer);
			}

			continue;
		} else if (bytesReceived < 0)
			break;

		dhcp_message *message = (dhcp_message *)buffer;
		if (message->transaction_id != htonl(fTransactionID)
			|| !message->HasOptions()
			|| memcmp(message->mac_address, discover.mac_address,
				discover.hardware_address_length)) {
			// this message is not for us
			continue;
		}

		switch (message->Type()) {
			case DHCP_NONE:
			default:
				// ignore this message
				break;

			case DHCP_OFFER:
			{
				// first offer wins
				if (state != INIT)
					break;

				// collect interface options

				fAssignedAddress = message->your_address;

				fConfiguration.MakeEmpty();
				fConfiguration.AddString("device", Device());
				fConfiguration.AddBool("auto", true);

				BMessage address;
				address.AddString("family", "inet");
				address.AddString("address", _ToString(fAssignedAddress));
				_ParseOptions(*message, address);

				fConfiguration.AddMessage("address", &address);

				// request configuration from the server

				_ResetTimeout(socket, timeout, tries);
				state = REQUESTING;
				_PrepareMessage(request, state);

				status = _SendMessage(socket, request, broadcast);
					// we're sending a broadcast so that all potential offers
					// get an answer
				break;
			}

			case DHCP_ACK:
			{
				if (state != REQUESTING && state != REBINDING
					&& state != RENEWAL)
					continue;

				// TODO: we might want to configure the stuff, don't we?
				BMessage address;
				_ParseOptions(*message, address);
					// TODO: currently, only lease time and DNS is updated this way

				// our address request has been acknowledged
				state = ACKNOWLEDGED;

				// configure interface
				BMessage reply;
				status = Target().SendMessage(&fConfiguration, &reply);
				if (status == B_OK)
					status = reply.FindInt32("status", &fStatus);
				break;
			}

			case DHCP_NACK:
				if (state != REQUESTING)
					continue;

				// try again (maybe we should prefer other servers if this
				// happens more than once)
				status = _SendMessage(socket, discover, broadcast);
				if (status == B_OK)
					state = INIT;
				break;
		}
	}

	close(socket);

	if (status == B_OK && fLeaseTime > 0) {
		// notify early enough when the lease is
		if (fRenewalTime == 0)
			fRenewalTime = fLeaseTime * 2/3;
		if (fRebindingTime == 0)
			fRebindingTime = fLeaseTime * 5/6;

		bigtime_t now = system_time();
		_RestartLease(fRenewalTime);

		fLeaseTime += now;
		fRenewalTime += now;
		fRebindingTime += now;
			// make lease times absolute
	} else {
		fLeaseTime = previousLeaseTime;
		bigtime_t now = system_time();
		fRenewalTime = (fLeaseTime - now) * 2/3 + now;
		fRebindingTime = (fLeaseTime - now) * 5/6 + now;
	}

	return status;
}