tool/CommandIp.cpp
changeset 2597 0e145bb05859
equal deleted inserted replaced
2596:d71acfbd7319 2597:0e145bb05859
       
     1 /*****************************************************************************
       
     2  *
       
     3  *  $Id$
       
     4  *
       
     5  *  Copyright (C) 2006-2014  Florian Pose, Ingenieurgemeinschaft IgH
       
     6  *
       
     7  *  This file is part of the IgH EtherCAT Master.
       
     8  *
       
     9  *  The IgH EtherCAT Master is free software; you can redistribute it and/or
       
    10  *  modify it under the terms of the GNU General Public License version 2, as
       
    11  *  published by the Free Software Foundation.
       
    12  *
       
    13  *  The IgH EtherCAT Master is distributed in the hope that it will be useful,
       
    14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General
       
    16  *  Public License for more details.
       
    17  *
       
    18  *  You should have received a copy of the GNU General Public License along
       
    19  *  with the IgH EtherCAT Master; if not, write to the Free Software
       
    20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
       
    21  *
       
    22  *  ---
       
    23  *
       
    24  *  The license mentioned above concerns the source code only. Using the
       
    25  *  EtherCAT technology and brand is only permitted in compliance with the
       
    26  *  industrial property and similar rights of Beckhoff Automation GmbH.
       
    27  *
       
    28  *  vim: expandtab
       
    29  *
       
    30  ****************************************************************************/
       
    31 
       
    32 #include <sys/types.h>
       
    33 #include <sys/socket.h>
       
    34 #include <netdb.h>
       
    35 
       
    36 #include <iostream>
       
    37 #include <algorithm>
       
    38 using namespace std;
       
    39 
       
    40 #include "CommandIp.h"
       
    41 #include "MasterDevice.h"
       
    42 
       
    43 /*****************************************************************************/
       
    44 
       
    45 CommandIp::CommandIp():
       
    46     Command("ip", "Set EoE IP parameters.")
       
    47 {
       
    48 }
       
    49 
       
    50 /*****************************************************************************/
       
    51 
       
    52 string CommandIp::helpString(const string &binaryBaseName) const
       
    53 {
       
    54     stringstream str;
       
    55 
       
    56     str << binaryBaseName << " " << getName() << " [OPTIONS] <ARGS>" << endl
       
    57         << endl
       
    58         << getBriefDescription() << endl
       
    59         << endl
       
    60         << "This command requires a single slave to be selected." << endl
       
    61         << endl
       
    62         << "IP parameters can be appended as argument pairs:" << endl
       
    63         << endl
       
    64         << "  addr <IPv4>[/prefix]  IP address (optionally with" << endl
       
    65         << "                        decimal subnet prefix)" << endl
       
    66         << "  link <MAC>            Link-layer address (may contain" << endl
       
    67         << "                        colons or hyphens)" << endl
       
    68         << "  default <IPv4>        Default gateway" << endl
       
    69         << "  dns <IPv4>            DNS server" << endl
       
    70         << "  name <hostname>       Host name (max. 32 byte)" << endl
       
    71         << endl
       
    72         << "IPv4 adresses can be given either in dot notation or as" << endl
       
    73         << "hostnames, which will be automatically resolved." << endl
       
    74         << endl
       
    75         << "Command-specific options:" << endl
       
    76         << "  --alias    -a <alias>" << endl
       
    77         << "  --position -p <pos>    Slave selection. See the help of" << endl
       
    78         << "                         the 'slaves' command." << endl
       
    79         << endl
       
    80         << numericInfo();
       
    81 
       
    82     return str.str();
       
    83 }
       
    84 
       
    85 /****************************************************************************/
       
    86 
       
    87 void CommandIp::execute(const StringVector &args)
       
    88 {
       
    89     if (args.size() <= 0) {
       
    90         return;
       
    91     }
       
    92 
       
    93     if (args.size() % 2) {
       
    94         stringstream err;
       
    95         err << "'" << getName() << "' needs an even number of arguments!";
       
    96         throwInvalidUsageException(err);
       
    97     }
       
    98 
       
    99     ec_ioctl_slave_eoe_ip_t io = {};
       
   100 
       
   101     for (unsigned int argIdx = 0; argIdx < args.size(); argIdx += 2) {
       
   102         string arg = args[argIdx];
       
   103         string val = args[argIdx + 1];
       
   104         std::transform(arg.begin(), arg.end(), arg.begin(), ::tolower);
       
   105 
       
   106         if (arg == "link") {
       
   107             parseMac(io.mac_address, val);
       
   108             io.mac_address_included = 1;
       
   109         }
       
   110         else if (arg == "addr") {
       
   111             parseIpv4Prefix(&io, val);
       
   112             io.ip_address_included = 1;
       
   113         }
       
   114         else if (arg == "default") {
       
   115             resolveIpv4(&io.gateway, val);
       
   116             io.gateway_included = 1;
       
   117         }
       
   118         else if (arg == "dns") {
       
   119             resolveIpv4(&io.dns, val);
       
   120             io.dns_included = 1;
       
   121         }
       
   122         else if (arg == "name") {
       
   123             if (val.size() > EC_MAX_HOSTNAME_SIZE - 1) {
       
   124                 stringstream err;
       
   125                 err << "Name too long!";
       
   126                 throwInvalidUsageException(err);
       
   127             }
       
   128             unsigned int i;
       
   129             for (i = 0; i < val.size(); i++) {
       
   130                 io.name[i] = val[i];
       
   131             }
       
   132             io.name[i] = 0;
       
   133             io.name_included = 1;
       
   134         }
       
   135         else {
       
   136             stringstream err;
       
   137             err << "Unknown argument '" << args[argIdx] << "'!";
       
   138             throwInvalidUsageException(err);
       
   139         }
       
   140     }
       
   141 
       
   142     MasterDevice m(getSingleMasterIndex());
       
   143     m.open(MasterDevice::ReadWrite);
       
   144     SlaveList slaves = selectedSlaves(m);
       
   145     if (slaves.size() != 1) {
       
   146         throwSingleSlaveRequired(slaves.size());
       
   147     }
       
   148     io.slave_position = slaves.front().position;
       
   149 
       
   150     // execute actual request
       
   151     try {
       
   152         m.setIpParam(&io);
       
   153     } catch (MasterDeviceException &e) {
       
   154         throw e;
       
   155     }
       
   156 }
       
   157 
       
   158 /*****************************************************************************/
       
   159 
       
   160 void CommandIp::parseMac(unsigned char mac[EC_ETH_ALEN], const string &str)
       
   161 {
       
   162     unsigned int pos = 0;
       
   163 
       
   164     for (unsigned int i = 0; i < EC_ETH_ALEN; i++) {
       
   165         if (pos + 2 > str.size()) {
       
   166             stringstream err;
       
   167             err << "Incomplete MAC address!";
       
   168             throwInvalidUsageException(err);
       
   169         }
       
   170 
       
   171         string byteStr = str.substr(pos, 2);
       
   172         pos += 2;
       
   173 
       
   174         stringstream s;
       
   175         s << byteStr;
       
   176         unsigned int byteValue;
       
   177         s >> hex >> byteValue;
       
   178         if (s.fail() || !s.eof() || byteValue > 0xff) {
       
   179             stringstream err;
       
   180             err << "Invalid MAC address!";
       
   181             throwInvalidUsageException(err);
       
   182         }
       
   183         mac[i] = byteValue;
       
   184 
       
   185         while (pos < str.size() && (str[pos] == ':' || str[pos] == '-')) {
       
   186             pos++;
       
   187         }
       
   188     }
       
   189 }
       
   190 
       
   191 /*****************************************************************************/
       
   192 
       
   193 void CommandIp::parseIpv4Prefix(ec_ioctl_slave_eoe_ip_t *io,
       
   194         const string &str)
       
   195 {
       
   196     size_t pos = str.find('/');
       
   197     string host;
       
   198 
       
   199     io->subnet_mask_included = pos != string::npos;
       
   200 
       
   201     if (pos == string::npos) { // no prefix found
       
   202         host = str;
       
   203     }
       
   204     else {
       
   205         host = str.substr(0, pos);
       
   206         string prefixStr = str.substr(pos + 1, string::npos);
       
   207         stringstream s;
       
   208         s << prefixStr;
       
   209         unsigned int prefix;
       
   210         s >> prefix;
       
   211         if (s.fail() || !s.eof() || prefix > 32) {
       
   212             stringstream err;
       
   213             err << "Invalid prefix '" << prefixStr << "'!";
       
   214             throwInvalidUsageException(err);
       
   215         }
       
   216         uint32_t mask = 0;
       
   217         for (unsigned int bit = 0; bit < prefix; bit++) {
       
   218             mask |= (1 << (31 - bit));
       
   219         }
       
   220         io->subnet_mask = htonl(mask);
       
   221     }
       
   222 
       
   223     resolveIpv4(&io->ip_address, host);
       
   224 }
       
   225 
       
   226 /*****************************************************************************/
       
   227 
       
   228 void CommandIp::resolveIpv4(uint32_t *addr, const string &str)
       
   229 {
       
   230     struct addrinfo hints = {};
       
   231     struct addrinfo *res;
       
   232 
       
   233     hints.ai_family = AF_INET; // only IPv4
       
   234 
       
   235     int ret = getaddrinfo(str.c_str(), NULL, &hints, &res);
       
   236     if (ret) {
       
   237         stringstream err;
       
   238         err << "Lookup of '" << str << "' failed: "
       
   239             << gai_strerror(ret) << endl;
       
   240         throwCommandException(err.str());
       
   241     }
       
   242 
       
   243     if (!res) { // returned list is empty
       
   244         stringstream err;
       
   245         err << "Lookup of '" << str << "' failed." << endl;
       
   246         throwCommandException(err.str());
       
   247     }
       
   248 
       
   249     sockaddr_in *sin = (sockaddr_in *) res->ai_addr;
       
   250     for (unsigned int i = 0; i < 4; i++) {
       
   251         ((unsigned char *) addr)[i] =
       
   252             ((unsigned char *) &sin->sin_addr.s_addr)[i];
       
   253     }
       
   254 
       
   255     freeaddrinfo(res);
       
   256 }
       
   257 
       
   258 /****************************************************************************/