#include "wpa_client.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace wifi { size_t strlcpy (char *dst, const char *src, size_t dst_sz) { size_t n; for (n = 0; n < dst_sz; n++) { if ((*dst++ = *src++) == '\0') break; } if (n < dst_sz) return n; if (n > 0) *(dst - 1) = '\0'; return n + strlen (src); } static std::string to_string(int val) { char *buf = NULL; int size; int temp; if (val < 0) { temp = -val; size = 2; } else { temp = val; size = 1; } for(; temp > 0; temp = temp / 10, size++); size++; buf = (char *)malloc(size); if (buf == NULL) { return ""; } memset(buf, 0, size); sprintf(buf, "%d", val); std::string re(buf); free(buf); return re; } MXDHCP::MXDHCP() { pstream = NULL; } MXDHCP::~MXDHCP() { if(pstream!=NULL) { pclose(pstream); pstream = NULL; } } bool MXDHCP::Start(const std::string & net_interface) { if(pstream!=NULL) { pclose(pstream); pstream = NULL; } std::string cmd = "udhcpc -b -i " + net_interface + " &"; system("killall -9 udhcpc &"); usleep(1000*100); pstream = popen(cmd.data(),"r"); if(pstream == NULL) { return false; } return true; } /* * dhcp 这个类的主要原理是通过读取udhcpc 的输出来判断是否拿到了ip地址,实际情况中可以使用别的方法 */ bool MXDHCP::GetDHCPStatus() { if(pstream == NULL) { return false; } int len = 1024; char *buff = (char *)malloc(sizeof(char)*len); if(buff==NULL) { return false; } int res = fread(buff,sizeof(char),len,pstream); if(res<=0) { free(buff); return false; } if(!CheckString(buff,res)) { free(buff); return false; } pclose(pstream); pstream = NULL; free(buff); return true; } bool MXDHCP::CheckString(char *buf ,int len) { if(strstr(buf,"adding dns")==NULL) { return false; } return true; } WPAClient::WPAClient(const std::string & wpa_control_path) { wpa_context_ = NULL; wpa_control_path_ = wpa_control_path; SetConnStatus(STEP_SCAN); Init(); } WPAClient::~WPAClient() { Close(wpa_context_); } bool WPAClient::Init() { wpa_context_ = Open(wpa_control_path_); if (wpa_context_ == NULL) { print_error("open wpa failed\n"); return false; } SetConnStatus(STEP_SCAN); return true; } std::string WPAClient::GetCurrentSSID() { std::string cmd = "STATUS"; std::string ssid_key = "\nssid="; std::string recv; std::string ssid = ""; if (!Request(wpa_context_, cmd, recv)) { return ""; } char temp[1024] = {0}; strcpy(temp, recv.data()); char *key = NULL; key = strstr(temp, ssid_key.data()); if (key == NULL) { return ""; } key += ssid_key.length(); for(; (*key != '\0') && (*key != '\n') && (*key != '\r'); key++) { ssid += *key; } return ssid; } std::string WPAClient::GetNetSsid() { std::string cmd = "SCAN"; std::string recv; if (!Request(wpa_context_, cmd, recv)) { return ""; } recv.clear(); cmd = "SCAN_RESULTS"; if (!Request(wpa_context_, cmd, recv)) { return ""; } return recv; } int WPAClient::GetWiFiRssi() { std::string cmd = "SIGNAL_POLL"; std::string rssi_key = "RSSI"; std::string recv; if (!Request(wpa_context_, cmd, recv)) { return 0; } char temp[1024] = {0}; strcpy(temp, recv.data()); print_info("recv = %s\n",recv.c_str()); char *key = NULL; key = strstr(temp, rssi_key.data()); if (key == NULL) { return 0; } for(; (*key != '\0') && (*key != '\n') && (*key != '\r'); key++) { if ((*key >= '0') && (*key <= '9')) { return atoi(key); } } return 0; } bool WPAClient::ConnectWiFi(const std::string & ssid, const std::string & password) { int net_id; SetConnStatus(STEP_SCAN); if (!CleanAllWiFi()) { return false; } print_info("CleanAllWiFi \n"); if (!AddWiFi(net_id)) { return false; } print_info("AddWiFi \n"); if (!SetSSID(ssid, net_id)) { return false; } print_info("SetSSID \n"); if (!SetPassword(password, 0)) { return false; } if (!SetProtocol(net_id, 1)) { return false; } print_info("SetProtocol\n"); SetScanSSID(net_id); if (!EnableWiFi(net_id)) { return false; } print_info("EnableWiFi\n"); return CheckCommandWithOk("SAVE_CONFIG"); //return true; } bool WPAClient::ConnectWiFiWithNoPassword(const std::string & ssid) { int net_id; SetConnStatus(STEP_SCAN); if (!CleanAllWiFi()) { return false; } print_info("CleanAllWiFi\n"); if (!AddWiFi(net_id)) { return false; } print_info("AddWiFi\n"); if (!SetSSID(ssid, net_id)) { return false; } print_info("SetSSID\n"); if (!SetProtocol(net_id, 0)) { return false; } print_info("SetProtocol\n"); SetScanSSID(net_id); if (!EnableWiFi(net_id)) { return false; } print_info("EnableWiFi\n"); return CheckCommandWithOk("SAVE_CONFIG"); } bool WPAClient::ConnectWiFiWithLast() { SetConnStatus(STEP_SCAN); if (!CheckCommandWithOk("ENABLE_NETWORK all")) { return false; } return true; } bool WPAClient::GetConnectStatus() { std::string cmd = "STATUS"; std::string recv; int addr; switch (step_) { case STEP_SCAN: if (!Request(wpa_context_, cmd, recv)) { return false; } addr = recv.find("COMPLETED"); if (addr == -1) { return false; } SetConnStatus(STEP_CONNECT_AP_OK); case STEP_CONNECT_AP_OK: if (!dhcp_.Start("wlan0")) { return false; } SetConnStatus(STEP_DHCP_IP); case STEP_DHCP_IP: if (!dhcp_.GetDHCPStatus()) { return false; } SetConnStatus(STEP_SUCCESS); case STEP_SUCCESS: return true; default: return false; } return false; } void WPAClient::SetConnStatus(ConnectStatus status) { step_ = status; } void WPAClient::wifiup() { system("ifconfig mlan0 up"); system("ifconfig mlan0 up"); system("ifconfig mlan0 up"); } bool WPAClient::CleanWifi() { bool flag = CleanAllWiFi(); CheckCommandWithOk("SAVE_CONFIG"); return flag; } int WPAClient::GetConnStatus() { return step_; } WPAContext * WPAClient::Open(const std::string & path) { struct WPAContext *ctrl; ctrl = (struct WPAContext*)malloc(sizeof(struct WPAContext)); if (ctrl == NULL) { print_error("malloc failed\n"); return NULL; } memset(ctrl, 0, sizeof(struct WPAContext)); static int counter = 0; int ret; int tries = 0; size_t res; ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0); if (ctrl->s < 0) { print_error("socket failed\n"); free(ctrl); return NULL; } ctrl->local.sun_family = AF_UNIX; counter++; try_again: ret = snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path), "/tmp" "/" "wpa_ctrl_" "%d-%d", (int)getpid(), counter); if (ret < 0 || (size_t)ret >= sizeof(ctrl->local.sun_path)) { print_error("snprintf failed\n"); close(ctrl->s); free(ctrl); return NULL; } tries++; if (bind(ctrl->s, (struct sockaddr *) &ctrl->local, sizeof(ctrl->local)) < 0) { if (errno == EADDRINUSE && tries < 2) { /* * getpid() returns unique identifier for this instance * of wpa_ctrl, so the existing socket file must have * been left by unclean termination of an earlier run. * Remove the file and try again. */ unlink(ctrl->local.sun_path); goto try_again; } print_error("bind failed\n"); close(ctrl->s); free(ctrl); return NULL; } ctrl->dest.sun_family = AF_UNIX; res = strlcpy(ctrl->dest.sun_path, wpa_control_path_.data(), sizeof(ctrl->dest.sun_path)); if (res >= sizeof(ctrl->dest.sun_path)) { close(ctrl->s); free(ctrl); return NULL; } if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest, sizeof(ctrl->dest)) < 0) { print_error("connect failed\n"); close(ctrl->s); unlink(ctrl->local.sun_path); free(ctrl); return NULL; } return ctrl; } void WPAClient::Close(WPAContext * context) { if (context == NULL) return; unlink(context->local.sun_path); if (context->s >= 0) close(context->s); free(context); } bool WPAClient::Request(WPAContext * context, const std::string & cmd, std::string& reply) { int res; fd_set rfds; struct timeval tv; const char *_cmd; char *cmd_buf = NULL; size_t _cmd_len; _cmd = cmd.data(); _cmd_len = cmd.length(); if (wpa_context_ == NULL) { print_error("wpa_context_ is null\n"); return false; } if (send(wpa_context_->s, _cmd, _cmd_len, 0) < 0) { free(cmd_buf); return -1; } free(cmd_buf); for (;;) { tv.tv_sec = 10; tv.tv_usec = 0; FD_ZERO(&rfds); FD_SET(wpa_context_->s, &rfds); res = select(wpa_context_->s + 1, &rfds, NULL, NULL, &tv); if (res < 0) return false; if (FD_ISSET(wpa_context_->s, &rfds)) { char temp[1024] = {0}; int temp_len = 1024; res = recv(wpa_context_->s, temp, temp_len, 0); if (res < 0) return false; if (res > 0 && temp[0] == '<') { continue; } reply = temp; break; } else { return false; } } return true; } bool WPAClient::CheckCommandWithOk(const std::string cmd) { std::string recv; if (!Request(wpa_context_, cmd, recv)) { print_error("send cmd falied\n"); return false; } print_error("recv cmd %s\n",recv.data()); if (strstr(recv.data(), "OK") == NULL) { return false; } return true; } bool WPAClient::AddWiFi(int & id) { std::string add_cmd = "ADD_NETWORK"; std::string recv; if (!Request(wpa_context_, add_cmd, recv)) { return false; } id = atoi(recv.data()); return true; } bool WPAClient::SetScanSSID(int id) { std::string cmd = "SET_NETWORK " + to_string(id) + " scan_ssid 1"; return CheckCommandWithOk(cmd); } bool WPAClient::SetSSID(const std::string & ssid, int id) { std::string cmd = "SET_NETWORK " + to_string(id) + " ssid " + "\"" + ssid + "\""; return CheckCommandWithOk(cmd); } bool WPAClient::SetPassword(const std::string & password, int id) { std::string cmd = "SET_NETWORK " + to_string(id) + " psk " + "\"" + password + "\""; return CheckCommandWithOk(cmd); } bool WPAClient::SetProtocol(int id, int en_crypt) { std::string cmd = "SET_NETWORK " + to_string(id); if (en_crypt) { cmd += " key_mgmt WPA-PSK"; return CheckCommandWithOk(cmd); } else { cmd += " key_mgmt NONE"; return CheckCommandWithOk(cmd); } } bool WPAClient::CleanAllWiFi() { CheckCommandWithOk("REMOVE_NETWORK all"); CheckCommandWithOk("DISABLE_NETWORK all"); return true; } bool WPAClient::EnableWiFi(int id) { std::string cmd = "ENABLE_NETWORK " + to_string(id); return CheckCommandWithOk(cmd); } bool WPAClient::ReconnectWiFi() { std::string cmd = "RECONNECT"; return CheckCommandWithOk(cmd); } }