1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <stdio.h> 18 #include <errno.h> 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 #include <arpa/inet.h> 22 #include <pthread.h> 23 24 #define LOG_TAG "DhcpClient" 25 #include <cutils/log.h> 26 #include <cutils/properties.h> 27 28 #include <sysutils/ServiceManager.h> 29 30 #include <netutils/ifc.h> 31 #include <netutils/dhcp.h> 32 33 #include "DhcpClient.h" 34 #include "DhcpState.h" 35 #include "DhcpListener.h" 36 #include "IDhcpEventHandlers.h" 37 #include "Controller.h" 38 39 DhcpClient::DhcpClient(IDhcpEventHandlers *handlers) : 40 mState(DhcpState::INIT), mHandlers(handlers) { 41 mServiceManager = new ServiceManager(); 42 mListener = NULL; 43 mListenerSocket = NULL; 44 mController = NULL; 45 mDoArpProbe = false; 46 pthread_mutex_init(&mLock, NULL); 47 } 48 49 DhcpClient::~DhcpClient() { 50 delete mServiceManager; 51 if (mListener) 52 delete mListener; 53 } 54 55 int DhcpClient::start(Controller *c) { 56 LOGD("Starting DHCP service (arp probe = %d)", mDoArpProbe); 57 char svc[PROPERTY_VALUE_MAX]; 58 snprintf(svc, 59 sizeof(svc), 60 "dhcpcd:%s%s", 61 (!mDoArpProbe ? "-A " : ""), 62 c->getBoundInterface()); 63 64 pthread_mutex_lock(&mLock); 65 66 if (mController) { 67 pthread_mutex_unlock(&mLock); 68 errno = EBUSY; 69 return -1; 70 } 71 mController = c; 72 73 sockaddr_in addr; 74 if ((mListenerSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) { 75 LOGE("Failed to create DHCP listener socket"); 76 pthread_mutex_unlock(&mLock); 77 return -1; 78 } 79 memset(&addr, 0, sizeof(addr)); 80 addr.sin_family = AF_INET; 81 addr.sin_addr.s_addr = inet_addr("127.0.0.1"); 82 addr.sin_port = htons(DhcpClient::STATUS_MONITOR_PORT); 83 84 if (bind(mListenerSocket, (struct sockaddr *) &addr, sizeof(addr))) { 85 LOGE("Failed to bind DHCP listener socket"); 86 close(mListenerSocket); 87 mListenerSocket = -1; 88 pthread_mutex_unlock(&mLock); 89 return -1; 90 } 91 92 if (mServiceManager->start(svc)) { 93 LOGE("Failed to start dhcp service"); 94 pthread_mutex_unlock(&mLock); 95 return -1; 96 } 97 98 mListener = new DhcpListener(mController, mListenerSocket, mHandlers); 99 if (mListener->startListener()) { 100 LOGE("Failed to start listener"); 101 #if 0 102 mServiceManager->stop("dhcpcd"); 103 return -1; 104 #endif 105 delete mListener; 106 mListener = NULL; 107 pthread_mutex_unlock(&mLock); 108 } 109 110 pthread_mutex_unlock(&mLock); 111 return 0; 112 } 113 114 int DhcpClient::stop() { 115 pthread_mutex_lock(&mLock); 116 if (!mController) { 117 pthread_mutex_unlock(&mLock); 118 return 0; 119 } 120 121 if (mListener) { 122 mListener->stopListener(); 123 delete mListener; 124 mListener = NULL; 125 } 126 close(mListenerSocket); 127 128 if (mServiceManager->stop("dhcpcd")) { 129 LOGW("Failed to stop DHCP service (%s)", strerror(errno)); 130 // XXX: Kill it the hard way.. but its gotta go! 131 } 132 133 mController = NULL; 134 pthread_mutex_unlock(&mLock); 135 return 0; 136 } 137 138 void DhcpClient::setDoArpProbe(bool probe) { 139 mDoArpProbe = probe; 140 } 141