void
UnicodeCharTest::_TestChar(uint32 i, Result result)
{
    char text[16];

    _ToString(i, text);
    CPPUNIT_ASSERT_EQUAL(BString(result.value), text);
    CPPUNIT_ASSERT_EQUAL(result.isAlpha, BUnicodeChar::IsAlpha(i));
    CPPUNIT_ASSERT_EQUAL(result.isAlNum, BUnicodeChar::IsAlNum(i));
    CPPUNIT_ASSERT_EQUAL(result.isLower, BUnicodeChar::IsLower(i));
    CPPUNIT_ASSERT_EQUAL(result.isUpper, BUnicodeChar::IsUpper(i));
    CPPUNIT_ASSERT_EQUAL(result.isDefined, BUnicodeChar::IsDefined(i));
    CPPUNIT_ASSERT_EQUAL(result.type, BUnicodeChar::Type(i));
    CPPUNIT_ASSERT_EQUAL(result.toUpper, BUnicodeChar::ToUpper(i));
    CPPUNIT_ASSERT_EQUAL(result.toLower, BUnicodeChar::ToLower(i));
}
Exemple #2
0
void
DHCPClient::_ParseOptions(dhcp_message& message, BMessage& address)
{
	dhcp_option_cookie cookie;
	message_option option;
	const uint8* data;
	size_t size;
	while (message.NextOption(cookie, option, data, size)) {
		// iterate through all options
		switch (option) {
			case OPTION_ROUTER_ADDRESS:
				address.AddString("gateway", _ToString(data));
				break;
			case OPTION_SUBNET_MASK:
				address.AddString("mask", _ToString(data));
				break;
			case OPTION_BROADCAST_ADDRESS:
				address.AddString("broadcast", _ToString(data));
				break;
			case OPTION_DOMAIN_NAME_SERVER:
			{
				// TODO: for now, we write it just out to resolv.conf
				BPath path;
				if (find_directory(B_COMMON_SETTINGS_DIRECTORY, &path) != B_OK)
					break;

				path.Append("network/resolv.conf");

				FILE* file = fopen(path.Path(), "w");
				for (uint32 i = 0; i < size / 4; i++) {
					syslog(LOG_INFO, "DNS: %s\n",
						_ToString(&data[i * 4]).String());
					if (file != NULL) {
						fprintf(file, "nameserver %s\n",
							_ToString(&data[i * 4]).String());
					}
				}
				fclose(file);
				break;
			}
			case OPTION_SERVER_ADDRESS:
				fServer.sin_addr.s_addr = *(in_addr_t*)data;
				break;

			case OPTION_ADDRESS_LEASE_TIME:
				syslog(LOG_INFO, "lease time of %lu seconds\n",
					htonl(*(uint32*)data));
				fLeaseTime = htonl(*(uint32*)data) * 1000000LL;
				break;
			case OPTION_RENEWAL_TIME:
				syslog(LOG_INFO, "renewal time of %lu seconds\n",
					htonl(*(uint32*)data));
				fRenewalTime = htonl(*(uint32*)data) * 1000000LL;
				break;
			case OPTION_REBINDING_TIME:
				syslog(LOG_INFO, "rebinding time of %lu seconds\n",
					htonl(*(uint32*)data));
				fRebindingTime = htonl(*(uint32*)data) * 1000000LL;
				break;

			case OPTION_HOST_NAME:
			{
				char name[256];
				memcpy(name, data, size);
				name[size] = '\0';
				syslog(LOG_INFO, "DHCP host name: \"%s\"\n", name);
				break;
			}

			case OPTION_DOMAIN_NAME:
			{
				char name[256];
				memcpy(name, data, size);
				name[size] = '\0';
				syslog(LOG_INFO, "DHCP domain name: \"%s\"\n", name);
				break;
			}

			case OPTION_MESSAGE_TYPE:
				break;

			default:
				syslog(LOG_INFO, "unknown option %lu\n", (uint32)option);
				break;
		}
	}
}
Exemple #3
0
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;
}