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)); }
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; } } }
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; }