1 // $Id$
2 // Copyright (c) 2001,2002 RIPE NCC
3 //
4 // All Rights Reserved
5 //
6 // Permission to use, copy, modify, and distribute this software and its
7 // documentation for any purpose and without fee is hereby granted,
8 // provided that the above copyright notice appear in all copies and that
9 // both that copyright notice and this permission notice appear in
10 // supporting documentation, and that the name of the author not be
11 // used in advertising or publicity pertaining to distribution of the
12 // software without specific, written prior permission.
13 //
14 // THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15 // ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS; IN NO EVENT SHALL
16 // AUTHOR BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY
17 // DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
18 // AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 //
21 //
22 // Copyright (c) 1994 by the University of Southern California
23 // All rights reserved.
24 //
25 // Permission is hereby granted, free of charge, to any person obtaining a copy
26 // of this software and associated documentation files (the "Software"), to deal
27 // in the Software without restriction, including without limitation the rights
28 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
29 // copies of the Software, and to permit persons to whom the Software is
30 // furnished to do so, subject to the following conditions:
31 //
32 // The above copyright notice and this permission notice shall be included in
33 // all copies or substantial portions of the Software.
34 //
35 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
36 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
37 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
38 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
39 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
40 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
41 // THE SOFTWARE.
42 //
43 // Questions concerning this software should be directed to
44 // irrtoolset@cs.usc.edu.
45 //
46 // Author(s): Cengiz Alaettinoglu <cengiz@ISI.EDU>
47
48 #include "config.h"
49 #include <cstdio>
50 #include "rpsl_attr.hh"
51 #include "object.hh"
52 #include "schema.hh"
53 #include <string>
54
55 using namespace std;
56
57 //// printing ////////////////////////////////////////////////////////
58
print(ostream & out) const59 ostream &Attr::print(ostream &out) const {
60 if (object && object->contents)
61 out.write(object->getTextAt(offset), len);
62 return out;
63 }
64
print(ostream & out) const65 ostream &AttrGeneric::print(ostream &out) const {
66 out << type->name() << ":\t" << *items;
67 return out;
68 }
69
print(ostream & out) const70 ostream &AttrImport::print(ostream &out) const {
71 out << "import: ";
72 if (fromProt && fromProt->name && strcasecmp(fromProt->name, "BGP4"))
73 out << "protocol " << fromProt->name << " ";
74 if (intoProt && intoProt->name && strcasecmp(intoProt->name, "BGP4"))
75 out << "into " << intoProt->name << " ";
76 out << *policy;
77 return out;
78 }
79
print(ostream & out) const80 ostream &AttrExport::print(ostream &out) const {
81 out << "export: ";
82 if (fromProt && fromProt->name && strcasecmp(fromProt->name, "BGP4"))
83 out << "protocol " << fromProt->name << " ";
84 if (intoProt && intoProt->name && strcasecmp(intoProt->name, "BGP4"))
85 out << "into " << intoProt->name << " ";
86 out << *policy;
87 return out;
88 }
89
print(ostream & out) const90 ostream &AttrDefault::print(ostream &out) const {
91 out << "default: \t" << *afi_list << " to " << *peering << "\n";
92
93 if (!action->isEmpty())
94 out << " \t " << *action << "\n";
95
96 if (filter && typeid(filter) != typeid(FilterANY))
97 out << " \t networks " << *filter;
98
99 return out;
100 }
101
print(ostream & out) const102 ostream &AttrFilter::print(ostream &out) const {
103 out << "filter: " << *filter;
104
105 return out;
106 }
print(ostream & out) const107 ostream &AttrMPPeval::print(ostream &out) const {
108 out << "filter: " << *filter;
109
110 return out;
111 }
112
113
print(ostream & out) const114 ostream &AttrPeering::print(ostream &out) const {
115 out << "peering: " << *peering;
116
117 return out;
118 }
119
print(ostream & out) const120 ostream &AttrIfAddr::print(ostream &out) const {
121 /* static char buffer[128];
122 out << "ifaddr:\t" << int2quad(buffer, ifaddr.get_ipaddr())
123 << " masklen " << ifaddr.get_length();
124 return out;
125 */
126 out << "ifaddr/interface:\t" ;
127 out << ifaddr->get_ip_text();
128 out << " masklen " << ifaddr->get_length();
129 if (action)
130 out << " action " << *action;
131 if (tunnel)
132 out << " tunnel " << *tunnel;
133 return out;
134 }
135
print(ostream & out) const136 ostream &AttrPeerOption::print(ostream &out) const {
137 out << option << "(" << *args << ")";
138 return out;
139 }
140
141 /*
142 ostream &AttrPeer::print(ostream &out) const {
143 out << "peer:\t" << protocol->name
144 << " " << *peer << " ";
145 for (AttrPeerOption *nd = options->head(); nd; ) {
146 nd->print(out);
147 nd = options->next(nd);
148 if (nd)
149 out << ", ";
150 }
151 return out;
152 }
153 */
154
print(ostream & out) const155 ostream &AttrPeer::print(ostream &out) const {
156 out << "peer/mp-peer:\t" << protocol->name
157 << " " << peer->get_ip_text() << " ";
158 for (AttrPeerOption *nd = options->head(); nd; ) {
159 nd->print(out);
160 nd = options->next(nd);
161 if (nd)
162 out << ", ";
163 }
164 return out;
165 }
166
print(ostream & out) const167 ostream &AttrTypedef::print(ostream &out) const {
168 if (type)
169 out << "typedef: " << name << " " << *type;
170 else
171 out << "typedef: " << name << "<error in type spec>";
172 return out;
173 }
174
print(ostream & out) const175 ostream &AttrProtocol::print(ostream &out) const {
176 out << "protocol: " << name;
177 for (AttrProtocolOption *nd = options->head(); nd; nd = options->next(nd)) {
178 nd->print(out);
179 out << "\n ";
180 }
181 return out;
182 }
183
print(ostream & out) const184 ostream &AttrProtocolOption::print(ostream &out) const {
185 out << (optional ? " optional " : " mandatory ") << *option << " ";
186 return out;
187 }
188
print(ostream & out) const189 ostream &AttrMethod::print(ostream &out) const {
190 out << name << "(";
191 for (RPTypeNode *n = args->head(); n; ) {
192 out << *n->type;
193 n = args->next(n);
194 if (n)
195 out << ", ";
196 }
197 if (varargs)
198 out << ", ...";
199 out << ")";
200 return out;
201 }
202
print(ostream & out) const203 ostream &AttrRPAttr::print(ostream &out) const {
204 out << "rp-attribute: " << name;
205 for (AttrMethod *nd = methods->head(); nd; nd = methods->next(nd))
206 out << " " << *nd;
207 return out;
208 }
209
print(ostream & out) const210 ostream &AttrAttr::print(ostream &out) const {
211 out << "attr: " << _name << " syntax(?) ?";
212
213 return out;
214 }
215
216
217
218
219
220
221
222
searchMethod(const char * name) const223 const AttrMethod *AttrRPAttr::searchMethod(const char *name) const {
224 char buffer[1024] = "";
225
226 if (!isalpha(*name))
227 strcpy(buffer, "operator");
228
229 strcat(buffer, name);
230
231 // return method or NULL
232 for (AttrMethod *m = methods->head(); m; m = methods->next(m))
233 if (!strcasecmp(m->name, buffer))
234 return m;
235
236 return NULL;
237 }
238
searchNextMethod(const AttrMethod * last) const239 const AttrMethod *AttrRPAttr::searchNextMethod(const AttrMethod *last) const {
240 // return method or NULL
241 const AttrMethod *m = last;
242
243 if (!last)
244 return NULL;
245
246 for (m = methods->next(m); m; m = methods->next(m))
247 if (!strcasecmp(m->name, last->name))
248 return m;
249
250 return NULL;
251 }
252
startMandatoryCheck()253 void AttrProtocol::startMandatoryCheck() {
254 for (AttrProtocolOption *m = options->head(); m; m = options->next(m))
255 m->found = false;
256 }
257
missingMandatoryOption()258 const AttrProtocolOption *AttrProtocol::missingMandatoryOption() {
259 AttrProtocolOption *m, *n;
260
261 for (m = options->head(); m; m = options->next(m)) {
262 if (! m->found && ! m->optional)
263 return m;
264 if (m->found)
265 for (n = options->next(m); n; n = options->next(n))
266 if (!strcasecmp(m->option->name, n->option->name))
267 n->found = true;
268 }
269
270 return NULL;
271 }
272
searchOption(const char * name) const273 const AttrProtocolOption *AttrProtocol::searchOption(const char *name) const {
274 // return method or NULL
275 for (AttrProtocolOption *m = options->head(); m; m = options->next(m))
276 if (!strcasecmp(m->option->name, name)) {
277 m->found = true;
278 return m;
279 }
280
281 return NULL;
282 }
283
searchNextOption(const AttrProtocolOption * last) const284 const AttrProtocolOption *AttrProtocol::searchNextOption
285 (const AttrProtocolOption *last) const {
286 // return method or NULL
287 AttrProtocolOption *m = (AttrProtocolOption *) last;
288
289 if (!last)
290 return NULL;
291
292 for (m = options->next(m); m; m = options->next(m))
293 if (!strcasecmp(m->option->name, last->option->name)) {
294 m->found = true;
295 return m;
296 }
297
298 return NULL;
299 }
300
searchOption(const char * name) const301 const AttrPeerOption *AttrPeer::searchOption(const char *name) const {
302 // return method or NULL
303 for (AttrPeerOption *m = options->head(); m; m = options->next(m))
304 if (!strcasecmp(m->option, name))
305 return m;
306
307 return NULL;
308 }
309
validateArgs(ItemList * actualArgs,int & position,const RPType * & correctType) const310 bool AttrMethod::validateArgs(ItemList *actualArgs, int &position,
311 const RPType *&correctType) const {
312 RPTypeNode *tnode = args->head();
313 Item *arg = actualArgs->head();
314 position = 0;
315 Item *arg2;
316
317 if (!tnode && !arg)
318 return true;
319
320 if (!tnode)
321 return false;
322
323 position = 1;
324 correctType = tnode->type;
325 while (correctType && arg) {
326 if (!correctType->validate(arg)) {
327 arg2 = correctType->typeCast(arg);
328 if (arg2) {
329 actualArgs->insertAfter(arg, arg2);
330 actualArgs->remove(arg);
331 delete arg;
332 arg = arg2;
333 } else
334 return false;
335 }
336
337 position++;
338 arg = actualArgs->next(arg);
339 tnode = args->next(tnode);
340 correctType = tnode ? tnode->type : NULL;
341 }
342
343 if (!correctType && arg && varargs) { // extra args
344 tnode = args->tail();
345 correctType = tnode->type;
346 while (correctType && arg) {
347 if (!correctType->validate(arg)) {
348 arg2 = correctType->typeCast(arg);
349 if (arg2) {
350 actualArgs->insertAfter(arg, arg2);
351 actualArgs->remove(arg);
352 delete arg;
353 arg = arg2;
354 } else
355 return false;
356 }
357
358 arg = actualArgs->next(arg);
359 position++;
360 }
361 correctType = (RPType *) NULL;
362 }
363
364 if (!correctType && !arg)
365 return true;
366
367 position = 0;
368 return false;
369 }
370
~AttrClass()371 AttrClass::~AttrClass() {
372 if (object)
373 delete object;
374 else
375 for (int i = 0; i < attribs.size(); ++i)
376 delete attribs[i];
377 free(name);
378 }
379
reset()380 void AttrClass::reset() {
381 for (int i = 0; i < attribs.size(); ++i)
382 attribs[i]->reset();
383 }
384
searchAttr(const char * name)385 AttrAttr* AttrClass::searchAttr(const char *name) {
386 for (int i = 0; i < attribs.size(); ++i)
387 if (!strcasecmp(name, attribs[i]->name())) {
388 attribs[i]->touch();
389 return attribs[i];
390 }
391
392 return NULL;
393 }
394
validate(std::string & errors)395 bool AttrClass::validate(std::string &errors) {
396 // return true if valid i.e. no error
397 static char buffer[1024];
398 bool result = true;
399
400 for (int i = 0; i < attribs.size(); ++i) {
401 if (!attribs[i]->testKey()) {
402 sprintf(buffer, "***Error: key attribute %s is not specified.\n",
403 attribs[i]->name());
404 errors += buffer;
405 result = false;
406 }
407 if ((!schema.isForgiving() || attribs[i]->isKey())
408 && !attribs[i]->testMandatory()) {
409 sprintf(buffer, "***Error: mandatory attribute %s is not specified.\n",
410 attribs[i]->name());
411 errors += buffer;
412 result = false;
413 }
414 if ((!schema.isForgiving() || attribs[i]->isKey())
415 && !attribs[i]->testSingleValued()) {
416 sprintf(buffer,
417 "***Error: single-valued attribute %s occurs multiple times.\n",
418 attribs[i]->name());
419 errors += buffer;
420 result = false;
421 }
422 }
423 return result;
424 }
425
print(ostream & out) const426 ostream& AttrClass::print(ostream &out) const {
427 return out;
428 }
429
print(ostream & out) const430 ostream& AttrMntRoutes::print(ostream &out) const {
431 out << "mnt-routes:";
432 for (MntPrfxPair *p = mntPrfxList->head(); p; p = mntPrfxList->next(p)) {
433 out << " " << p->mnt;
434 if (p->prefixes)
435 out << " " << p->prefixes;
436 out << ",\n";
437 }
438 return out;
439 }
440
print(ostream & out) const441 ostream& AttrTRLabel::print(ostream &out) const {
442 out << "transaction-label: "
443 << *source << " " << *seq << " " << *stamp;
444 return out;
445 }
446
operator <<(ostream & stream,const Tunnel & p)447 ostream& operator<<(ostream& stream, const Tunnel& p) {
448 stream << p.remote_ip->get_ip_text() << " ";
449 if (p.encapsulation)
450 stream << *p.encapsulation ;
451 return stream;
452 }
453
454