blob: 9e6e28b67a83a0e16a43baf0369f99b378dc95f1 [file] [log] [blame]
Arman Ugurayf4c61812013-01-10 18:58:39 -08001// Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
Ben Chanb39cb312012-11-01 22:55:25 -07002// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Arman Uguray73a83e62013-02-12 18:51:33 -08005// Implements shill::CellularOperatorInfo. See cellular_operator_info.h for
6// details.
7
Ben Chanb39cb312012-11-01 22:55:25 -07008#include "shill/cellular_operator_info.h"
9
Arman Uguray73a83e62013-02-12 18:51:33 -080010#include <base/stl_util.h>
Arman Ugurayf4c61812013-01-10 18:58:39 -080011#include <base/string_number_conversions.h>
12#include <base/string_split.h>
13#include <base/string_util.h>
14
Arman Ugurayf4c61812013-01-10 18:58:39 -080015#include "shill/logging.h"
16
Albert Chaulk0e1cdea2013-02-27 15:32:55 -080017using base::FilePath;
Arman Ugurayf4c61812013-01-10 18:58:39 -080018using std::map;
Ben Chanb39cb312012-11-01 22:55:25 -070019using std::string;
Arman Ugurayf4c61812013-01-10 18:58:39 -080020using std::vector;
Ben Chanb39cb312012-11-01 22:55:25 -070021
22namespace shill {
23
24namespace {
25
Arman Uguray73a83e62013-02-12 18:51:33 -080026typedef vector<const CellularOperatorInfo::CellularOperator *>
27 ConstOperatorVector;
Ben Chanb39cb312012-11-01 22:55:25 -070028
Arman Uguray73a83e62013-02-12 18:51:33 -080029string FormattedMCCMNC(const string &mccmnc) {
Arman Ugurayf4c61812013-01-10 18:58:39 -080030 return "[MCCMNC=" + mccmnc + "]";
31}
32
Arman Uguray73a83e62013-02-12 18:51:33 -080033string FormattedSID(const string &sid) {
Arman Ugurayf4c61812013-01-10 18:58:39 -080034 return "[SID=" + sid + "]";
35}
36
Arman Uguray73a83e62013-02-12 18:51:33 -080037template <class Collection>
38const typename Collection::value_type::second_type *FindOrNull(
39 const Collection &collection,
40 const typename Collection::value_type::first_type &key) {
41 typename Collection::const_iterator it = collection.find(key);
42 if (it == collection.end())
Arman Ugurayf4c61812013-01-10 18:58:39 -080043 return NULL;
Arman Ugurayf4c61812013-01-10 18:58:39 -080044 return &it->second;
45}
46
Arman Uguray73a83e62013-02-12 18:51:33 -080047typedef CellularOperatorInfo COI;
48bool ParseNameLine(const string &value, COI::LocalizedName *name) {
Arman Ugurayf4c61812013-01-10 18:58:39 -080049 vector<string> fields;
50 base::SplitString(value, ',', &fields);
51 if (fields.size() != 2) {
52 LOG(ERROR) << "Badly formed \"name\" entry.";
53 return false;
54 }
55 name->language = fields[0];
56 name->name = fields[1];
57 return true;
58}
59
Arman Uguray73a83e62013-02-12 18:51:33 -080060// Advances the file reader to the next line that is neither a line comment
61// nor empty and returns it in |line|. If the end of file is reached, returns
62// false.
63bool AdvanceToNextValidLine(FileReader &file_reader, string *line) {
64 while (file_reader.ReadLine(line)) {
65 TrimWhitespaceASCII(*line, TRIM_ALL, line);
66 // Skip line comments.
67 if ((*line)[0] == '#' || line->empty())
68 continue;
69 // If line consists of a single null character, skip
70 if (line->length() == 1 && (*line)[0] == '\0')
71 continue;
72 return true;
Arman Ugurayf4c61812013-01-10 18:58:39 -080073 }
Arman Uguray73a83e62013-02-12 18:51:33 -080074 return false;
Arman Ugurayf4c61812013-01-10 18:58:39 -080075}
76
Arman Uguray73a83e62013-02-12 18:51:33 -080077// Splits |line| into two strings, separated with the |key_value_delimiter|.
78// Returns |false| if line does not contain |key_value_delimiter|, otherwise
79// returns the first substring in |key| and the second substring in |value|,
80// and returns true.
81bool ParseKeyValue(const string &line,
82 char key_value_delimiter,
83 std::string *key,
84 std::string *value) {
85 const size_t length = line.length();
86 for (size_t i = 0; i < length; ++i) {
87 if (line[i] == key_value_delimiter) {
88 key->assign(line, 0, i);
89 value->assign(line, i + 1, length-i);
90 return true;
91 }
Arman Ugurayf4c61812013-01-10 18:58:39 -080092 }
Arman Uguray73a83e62013-02-12 18:51:33 -080093 LOG(ERROR) << "Badly formed line: " << line;
94 return false;
95}
Arman Ugurayf4c61812013-01-10 18:58:39 -080096
Arman Uguray73a83e62013-02-12 18:51:33 -080097} // namespace
98
99class CellularOperatorInfoImpl {
100 public:
101 CellularOperatorInfoImpl() {
102 key_to_handler_["provider"] = new ProviderHandler(this);
103 key_to_handler_["mccmnc"] = new MccmncHandler(this);
104 key_to_handler_["name"] = new NameHandler(this);
105 key_to_handler_["apn"] = new ApnHandler(this);
106 key_to_handler_["sid"] = new SidHandler(this);
107 key_to_handler_["olp"] = new OlpHandler(this);
108 key_to_handler_["identifier"] = new IdentifierHandler(this);
Arman Uguray8ec7ea52013-04-30 02:00:23 -0700109 key_to_handler_["activation-code"] = new ActivationCodeHandler(this);
Arman Uguray73a83e62013-02-12 18:51:33 -0800110 key_to_handler_["country"] = new CountryHandler(this);
111 }
112
113 ~CellularOperatorInfoImpl() {
114 STLDeleteContainerPairSecondPointers(key_to_handler_.begin(),
115 key_to_handler_.end());
116 }
117
118 private:
119 struct ParserState {
120 ParserState() : provider(NULL), apn(NULL), parsing_apn(false) {}
121
122 void Clear() {
123 country.clear();
124 provider = NULL;
125 apn = NULL;
126 parsing_apn = false;
127 }
128
129 std::string country;
130 COI::CellularOperator *provider;
131 COI::MobileAPN *apn;
132
133 bool parsing_apn;
134 };
135
136 class KeyHandler {
137 public:
138 KeyHandler(CellularOperatorInfoImpl *info_impl) : info_impl_(info_impl) {}
139 virtual ~KeyHandler() {}
140
141 virtual bool HandleKey(const string &value) = 0;
142
143 protected:
144 CellularOperatorInfoImpl *info_impl() const { return info_impl_; }
145
146 private:
147 CellularOperatorInfoImpl *info_impl_;
148
149 DISALLOW_COPY_AND_ASSIGN(KeyHandler);
150 };
151
152 class CountryHandler : public KeyHandler {
153 public:
154 CountryHandler(CellularOperatorInfoImpl *info_impl)
155 : KeyHandler(info_impl) {}
156
157 bool HandleKey(const string &value) {
158 return info_impl()->HandleCountry(value);
159 }
160
161 private:
162 DISALLOW_COPY_AND_ASSIGN(CountryHandler);
163 };
164
165 class NameHandler : public KeyHandler {
166 public:
167 NameHandler(CellularOperatorInfoImpl *info_impl)
168 : KeyHandler(info_impl) {}
169
170 bool HandleKey(const string &value) {
171 return info_impl()->HandleNameKey(value);
172 }
173
174 private:
175 DISALLOW_COPY_AND_ASSIGN(NameHandler);
176 };
177
178 class ProviderHandler : public KeyHandler {
179 public:
180 ProviderHandler(CellularOperatorInfoImpl *info_impl)
181 : KeyHandler(info_impl) {}
182
183 bool HandleKey(const string &value) {
184 return info_impl()->HandleProvider(value);
185 }
186
187 private:
188 DISALLOW_COPY_AND_ASSIGN(ProviderHandler);
189 };
190
191 class MccmncHandler : public KeyHandler {
192 public:
193 MccmncHandler(CellularOperatorInfoImpl *info_impl)
194 : KeyHandler(info_impl) {}
195
196 bool HandleKey(const string &value) {
197 return info_impl()->HandleMCCMNC(value);
198 }
199
200 private:
201 DISALLOW_COPY_AND_ASSIGN(MccmncHandler);
202 };
203
204 class IdentifierHandler : public KeyHandler {
205 public:
206 IdentifierHandler(CellularOperatorInfoImpl *info_impl)
207 : KeyHandler(info_impl) {}
208
209 bool HandleKey(const string &value) {
210 return info_impl()->HandleIdentifier(value);
211 }
212
213 private:
214 DISALLOW_COPY_AND_ASSIGN(IdentifierHandler);
215 };
216
Arman Uguray8ec7ea52013-04-30 02:00:23 -0700217 class ActivationCodeHandler : public KeyHandler {
218 public:
219 ActivationCodeHandler(CellularOperatorInfoImpl *info_impl)
220 : KeyHandler(info_impl) {}
221
222 bool HandleKey(const string &value) {
223 return info_impl()->HandleActivationCode(value);
224 }
225
226 private:
227 DISALLOW_COPY_AND_ASSIGN(ActivationCodeHandler);
228 };
229
Arman Uguray73a83e62013-02-12 18:51:33 -0800230 class ApnHandler : public KeyHandler {
231 public:
232 ApnHandler(CellularOperatorInfoImpl *info_impl)
233 : KeyHandler(info_impl) {}
234
235 bool HandleKey(const string &value) {
236 return info_impl()->HandleAPN(value);
237 }
238
239 private:
240 DISALLOW_COPY_AND_ASSIGN(ApnHandler);
241 };
242
243 class SidHandler : public KeyHandler {
244 public:
245 SidHandler(CellularOperatorInfoImpl *info_impl)
246 : KeyHandler(info_impl) {}
247
248 bool HandleKey(const string &value) {
249 return info_impl()->HandleSID(value);
250 }
251
252 private:
253 DISALLOW_COPY_AND_ASSIGN(SidHandler);
254 };
255
256 class OlpHandler : public KeyHandler {
257 public:
258 OlpHandler(CellularOperatorInfoImpl *info_impl)
259 : KeyHandler(info_impl) {}
260
261 bool HandleKey(const string &value) {
262 return info_impl()->HandleOLP(value);
263 }
264
265 private:
266 DISALLOW_COPY_AND_ASSIGN(OlpHandler);
267 };
268
269 bool HandleFirstLine(FileReader &reader) {
270 // Read until the first line that is not a line comment.
271 string line;
272 if (!AdvanceToNextValidLine(reader, &line))
273 return false;
274
275 string key, value;
276 if (!ParseKeyValue(line, ':', &key, &value))
277 return false;
278
279 if (key != "serviceproviders") {
280 LOG(ERROR) << "File does not begin with \"serviceproviders\" "
281 << "entry.";
282 return false;
283 }
284 if (value != "3.0") {
285 LOG(ERROR) << "Unrecognized serviceproviders format.";
286 return false;
287 }
288 return true;
289 }
290
291 bool HandleCountry(const string &value) {
292 state_.country = value;
293 return true;
294 }
295
296 bool HandleNameKey(const string &value) {
297 if (state_.parsing_apn)
298 return HandleAPNName(value);
299 return HandleName(value);
300 }
301
302 bool HandleProvider(const string &value) {
303 state_.parsing_apn = false;
304
305 vector<string> fields;
306 base::SplitString(value, ',', &fields);
307 if (fields.size() != 4) {
308 LOG(ERROR) << "Badly formed \"provider\" entry.";
309 return false;
310 }
311
312 int is_primary = 0;
313 if (!base::StringToInt(fields[2], &is_primary)) {
314 LOG(ERROR) << "Badly formed value for \"is_primary\": " << fields[2];
315 return false;
316 }
317 int requires_roaming = 0;
318 if (!base::StringToInt(fields[3], &requires_roaming)) {
319 LOG(ERROR) << "Badly formed value for \"requires_roaming\": "
320 << fields[3];
321 return false;
322 }
323 state_.provider = new COI::CellularOperator();
324 state_.provider->is_primary_ = is_primary != 0;
325 state_.provider->requires_roaming_ = requires_roaming != 0;
326 state_.provider->country_ = state_.country;
327
328 operators_.push_back(state_.provider);
329 return true;
330 }
331
332 bool HandleMCCMNC(const string &value) {
333 if (value.empty()) {
334 LOG(ERROR) << "Empty \"mccmnc\" value.";
335 return false;
336 }
337 if (!state_.provider) {
338 LOG(ERROR) << "Found \"mccmnc\" entry without \"provider\".";
339 return false;
340 }
341
342 vector<string> mccmnc_list;
343 base::SplitString(value, ',', &mccmnc_list);
344 if ((mccmnc_list.size() % 2) != 0) {
345 LOG(ERROR) << "Badly formatted \"mccmnc\" entry. "
346 << "Expected even number of elements.";
347 return false;
348 }
349
350 for (size_t i = 0; i < mccmnc_list.size(); i += 2) {
351 const string &mccmnc = mccmnc_list[i];
352 if (!mccmnc.empty()) {
353 state_.provider->mccmnc_list_.push_back(mccmnc);
354 mccmnc_to_operator_[mccmnc] = state_.provider;
355 int index = -1;
356 if (base::StringToInt(mccmnc_list[i + 1], &index))
357 state_.provider->mccmnc_to_olp_idx_[mccmnc] = index;
358 }
359 }
360 return true;
361 }
362
363 bool HandleIdentifier(const string &value) {
364 if (!state_.provider) {
365 LOG(ERROR) << "Found \"identifier\" entry without \"provider\".";
366 return false;
367 }
368 state_.provider->identifier_ = value;
369 return true;
370 }
371
Arman Uguray8ec7ea52013-04-30 02:00:23 -0700372 bool HandleActivationCode(const string &value) {
373 if (!state_.provider) {
374 LOG(ERROR) << "Found \"activation-code\" entry without \"provider\".";
375 return false;
376 }
377 state_.provider->activation_code_ = value;
378 return true;
379 }
380
Arman Uguray73a83e62013-02-12 18:51:33 -0800381 bool HandleAPN(const string &value) {
382 if (!state_.provider) {
383 LOG(ERROR) << "Found \"apn\" entry without \"provider\".";
384 return false;
385 }
386 vector<string> fields;
387 base::SplitString(value, ',', &fields);
388 if (fields.size() != 4) {
389 LOG(ERROR) << "Badly formed \"apn\" entry.";
390 return false;
391 }
392 state_.apn = new COI::MobileAPN();
393 state_.apn->apn = fields[1];
394 state_.apn->username = fields[2];
395 state_.apn->password = fields[3];
396 state_.provider->apn_list_.push_back(state_.apn);
397 state_.parsing_apn = true;
398 return true;
399 }
400
401 bool HandleAPNName(const string &value) {
402 if (!(state_.parsing_apn && state_.apn)) {
403 LOG(ERROR) << "APN not being parsed.";
404 return false;
405 }
406 COI::LocalizedName name;
407 if (!ParseNameLine(value, &name))
408 return false;
409 state_.apn->name_list.push_back(name);
410 return true;
411 }
412
413 bool HandleName(const string &value) {
414 if (!state_.provider) {
415 LOG(ERROR) << "Found \"name\" entry without \"provider\".";
416 return false;
417 }
418
419 COI::LocalizedName name;
420 if (!ParseNameLine(value, &name))
421 return false;
422
423 if (state_.provider->name_list_.size() == 0) {
424 ConstOperatorVector &matching_operators =
425 name_to_operators_[name.name];
426 matching_operators.push_back(state_.provider);
427 }
428 state_.provider->name_list_.push_back(name);
429 return true;
430 }
431
432 bool HandleSID(const string &value) {
433 if (value.empty()) {
434 LOG(ERROR) << "Empty \"sid\" value.";
435 return false;
436 }
437 if (!state_.provider) {
438 LOG(ERROR) << "Found \"sid\" entry without \"provider\".";
439 return false;
440 }
441 vector<string> sid_list;
442 base::SplitString(value, ',', &sid_list);
443 if ((sid_list.size() % 2) != 0) {
444 LOG(ERROR) << "Badly formatted \"sid\" entry. "
445 << "Expected even number of elements. ";
446 return false;
447 }
448
449 for (size_t i = 0; i < sid_list.size(); i += 2) {
450 const string &sid = sid_list[i];
451 if (!sid.empty()) {
452 state_.provider->sid_list_.push_back(sid);
453 sid_to_operator_[sid] = state_.provider;
454 int index = -1;
455 if (base::StringToInt(sid_list[i + 1], &index))
456 state_.provider->sid_to_olp_idx_[sid] = index;
457 }
458 }
459 return true;
460 }
461
462 bool HandleOLP(const string &value) {
463 if (!state_.provider) {
464 LOG(ERROR) << "Found \"olp\" entry without \"provider\"";
465 return false;
466 }
467 vector<string> fields;
468 base::SplitString(value, ',', &fields);
469 if (fields.size() != 3) {
470 LOG(ERROR) << "Badly formed \"apn\" entry.";
471 return false;
472 }
473 CellularService::OLP *olp = new CellularService::OLP();
474 olp->SetMethod(fields[0]);
475 olp->SetURL(fields[1]);
476 olp->SetPostData(fields[2]);
477
478 state_.provider->olp_list_.push_back(olp);
479 return true;
480 }
481
482 void ClearOperators() {
483 operators_.clear();
484 mccmnc_to_operator_.clear();
485 sid_to_operator_.clear();
486 name_to_operators_.clear();
487 }
488
489 bool HandleKeyValue(const string &key, const string &value) {
490 KeyHandler * const *handler = FindOrNull(key_to_handler_, key);
491 if (!handler) {
492 LOG(ERROR) << "Invalid key \"" << key << "\".";
493 return false;
494 }
495 return (*handler)->HandleKey(value);
496 }
497
498 bool Load(const FilePath &info_file_path) {
499 // Clear any previus operators.
500 ClearOperators();
501
502 FileReader file_reader;
503 if (!file_reader.Open(info_file_path)) {
504 LOG(ERROR) << "Could not open operator info file.";
505 return false;
506 }
507
508 // See data/cellular_operator_info for the format of file contents.
509
510 state_.Clear();
511
512 if (!HandleFirstLine(file_reader))
513 return false;
514
515 string line;
516 while (true) {
517 if (!AdvanceToNextValidLine(file_reader, &line))
518 break;
519
520 string key, value;
521 if (!ParseKeyValue(line, ':', &key, &value)) {
522 ClearOperators();
523 return false;
524 }
525
526 if (!HandleKeyValue(key, value)) {
527 LOG(ERROR) << "Failed to parse \"" << key << "\" entry.";
528 ClearOperators();
529 return false;
530 }
531 }
532 return true;
533 }
534
535 private:
536 friend class CellularOperatorInfo;
537
538 ParserState state_;
539
540 ScopedVector<COI::CellularOperator> operators_;
541 map<string, COI::CellularOperator *> mccmnc_to_operator_;
542 map<string, COI::CellularOperator *> sid_to_operator_;
543 map<string, ConstOperatorVector> name_to_operators_;
544
545 map<string, KeyHandler *> key_to_handler_;
546
547 DISALLOW_COPY_AND_ASSIGN(CellularOperatorInfoImpl);
548};
549
Arman Uguray72fab6a2013-01-10 19:32:42 -0800550COI::LocalizedName::LocalizedName() {}
551COI::LocalizedName::LocalizedName(string name,
552 string language)
553 : name(name),
554 language(language) {}
555
Arman Uguray73a83e62013-02-12 18:51:33 -0800556CellularOperatorInfo::CellularOperator::CellularOperator()
557 : is_primary_(false),
558 requires_roaming_(false) {}
559
560CellularOperatorInfo::CellularOperatorInfo()
561 : impl_(new CellularOperatorInfoImpl()) {}
562CellularOperatorInfo::~CellularOperatorInfo() {}
563
564const ScopedVector<CellularOperatorInfo::CellularOperator> &
565CellularOperatorInfo::operators() const {
566 return impl_->operators_;
567}
568
569const CellularOperatorInfo::CellularOperator *
570CellularOperatorInfo::GetCellularOperatorByMCCMNC(const string &mccmnc) const {
571 SLOG(Cellular, 2) << __func__ << "(" << FormattedMCCMNC(mccmnc) << ")";
572
573 CellularOperator * const *provider =
574 FindOrNull(impl_->mccmnc_to_operator_, mccmnc);
575 if (!provider) {
576 LOG(ERROR) << "Operator with " << FormattedMCCMNC(mccmnc)
577 << " not found.";
578 return NULL;
579 }
580 return *provider;
581}
582
583const CellularOperatorInfo::CellularOperator *
584CellularOperatorInfo::GetCellularOperatorBySID(const string &sid) const {
585 SLOG(Cellular, 2) << __func__ << "(" << FormattedSID(sid) << ")";
586
587 CellularOperator * const *provider = FindOrNull(impl_->sid_to_operator_, sid);
588 if (!provider) {
589 LOG(ERROR) << "Operator with " << FormattedSID(sid) << " not found.";
590 return NULL;
591 }
592 return *provider;
593}
594
595const ConstOperatorVector *CellularOperatorInfo::GetCellularOperators(
596 const string &name) const {
597 SLOG(Cellular, 2) << __func__ << "(" << name << ")";
598
599 const ConstOperatorVector *providers =
600 FindOrNull(impl_->name_to_operators_, name);
601 if (!providers) {
602 LOG(ERROR) << "Given name \"" << name << "\" did not match any operators.";
603 return NULL;
604 }
605 return providers;
606}
607
608const CellularService::OLP *
609CellularOperatorInfo::GetOLPByMCCMNC(const string &mccmnc) const {
610 SLOG(Cellular, 2) << __func__ << "(" << FormattedMCCMNC(mccmnc) << ")";
611
612 const CellularOperator *provider = GetCellularOperatorByMCCMNC(mccmnc);
613 if (!provider)
614 return NULL;
615
616 const uint32 *indexptr = FindOrNull(provider->mccmnc_to_olp_idx_, mccmnc);
617 if (!indexptr)
618 return NULL;
619
620 uint32 index = *indexptr;
621 if (index >= provider->olp_list_.size()) {
622 LOG(ERROR) << "Invalid OLP index found for "
623 << FormattedMCCMNC(mccmnc) << ".";
624 return NULL;
625 }
626
627 return provider->olp_list_[index];
628}
629
630const CellularService::OLP *
631CellularOperatorInfo::GetOLPBySID(const string &sid) const {
632 SLOG(Cellular, 2) << __func__ << "(" << FormattedSID(sid) << ")";
633
634 const CellularOperator *provider = GetCellularOperatorBySID(sid);
635 if (!provider)
636 return NULL;
637
638 const uint32 *indexptr = FindOrNull(provider->sid_to_olp_idx_, sid);
639 if (!indexptr)
640 return NULL;
641
642 uint32 index = *indexptr;
643 if (index >= provider->olp_list_.size()) {
644 LOG(ERROR) << "Invalid OLP index found for " << FormattedSID(sid) << ".";
645 return NULL;
646 }
647
648 return provider->olp_list_[index];
649}
650
651bool CellularOperatorInfo::Load(const FilePath &info_file_path) {
652 SLOG(Cellular, 2) << __func__ << "(" << info_file_path.value() << ")";
653 return impl_->Load(info_file_path);
Ben Chanb39cb312012-11-01 22:55:25 -0700654}
655
656} // namespace shill