• Main Page
  • Related Pages
  • Namespaces
  • Data Structures
  • Files
  • File List
  • Globals

LogFilter.cc

Go to the documentation of this file.
00001 /** @file
00002 
00003   A brief file description
00004 
00005   @section license License
00006 
00007   Licensed to the Apache Software Foundation (ASF) under one
00008   or more contributor license agreements.  See the NOTICE file
00009   distributed with this work for additional information
00010   regarding copyright ownership.  The ASF licenses this file
00011   to you under the Apache License, Version 2.0 (the
00012   "License"); you may not use this file except in compliance
00013   with the License.  You may obtain a copy of the License at
00014 
00015       http://www.apache.org/licenses/LICENSE-2.0
00016 
00017   Unless required by applicable law or agreed to in writing, software
00018   distributed under the License is distributed on an "AS IS" BASIS,
00019   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00020   See the License for the specific language governing permissions and
00021   limitations under the License.
00022  */
00023 
00024 /***************************************************************************
00025  LogFilter.cc
00026 
00027 
00028  ***************************************************************************/
00029 #include "libts.h"
00030 
00031 #include "Error.h"
00032 #include "LogUtils.h"
00033 #include "LogFilter.h"
00034 #include "LogField.h"
00035 #include "LogFormat.h"
00036 #include "LogFile.h"
00037 #include "LogBuffer.h"
00038 #include "LogHost.h"
00039 #include "LogObject.h"
00040 #include "LogConfig.h"
00041 #include "Log.h"
00042 //#include "ink_ctype.h"
00043 #include "SimpleTokenizer.h"
00044 
00045 const char *LogFilter::OPERATOR_NAME[] = { "MATCH", "CASE_INSENSITIVE_MATCH","CONTAIN", "CASE_INSENSITIVE_CONTAIN" };
00046 const char *LogFilter::ACTION_NAME[] = { "REJECT", "ACCEPT", "WIPE_FIELD_VALUE" };
00047 
00048 /*-------------------------------------------------------------------------
00049   LogFilter::LogFilter
00050 
00051   note: it may be convenient to have the LogFilter constructor access the
00052   global_field_list to get the log field, but this is an unnecessary dependency
00053   between the classes and I think should be removed.     ltavera
00054   -------------------------------------------------------------------------*/
00055 LogFilter::LogFilter(const char *name, LogField * field, LogFilter::Action action, LogFilter::Operator oper)
00056   : m_name(ats_strdup(name)), m_field(NULL) , m_action(action), m_operator(oper), m_type(INT_FILTER), m_num_values(0)
00057 {
00058   m_field = new LogField(*field);
00059   ink_assert(m_field);
00060 }
00061 
00062 /*-------------------------------------------------------------------------
00063   LogFilter::~LogFilter
00064   -------------------------------------------------------------------------*/
00065 LogFilter::~LogFilter()
00066 {
00067   ats_free(m_name);
00068   delete m_field;
00069 }
00070 
00071 
00072 /*-------------------------------------------------------------------------
00073   LogFilterString::LogFilterString
00074   -------------------------------------------------------------------------*/
00075 void
00076 LogFilterString::_setValues(size_t n, char **value)
00077 {
00078   m_type = STRING_FILTER;
00079   m_num_values = n;
00080   if (n) {
00081     m_value = new char *[n];
00082     m_value_uppercase = new char *[n];
00083     m_length = new size_t[n];
00084     ink_assert(m_value && m_value_uppercase && m_length);
00085     for (size_t i = 0; i < n; ++i) {
00086       m_value[i] = ats_strdup(value[i]);
00087       m_length[i] = strlen(value[i]);
00088       m_value_uppercase[i] = (char *)ats_malloc((unsigned int) m_length[i] + 1);
00089       size_t j;
00090       for (j = 0; j < m_length[i]; ++j) {
00091         m_value_uppercase[i][j] = ParseRules::ink_toupper(m_value[i][j]);
00092       }
00093       m_value_uppercase[i][j] = 0;
00094     }
00095   }
00096 }
00097 
00098 
00099 LogFilterString::LogFilterString(const char *name, LogField * field,
00100                                  LogFilter::Action action, LogFilter::Operator oper, char *values)
00101   : LogFilter(name, field, action, oper)
00102 {
00103   // parse the comma-separated list of values and construct array
00104   //
00105   char **val_array = 0;
00106   size_t i = 0;
00107   SimpleTokenizer tok(values, ',');
00108   size_t n = tok.getNumTokensRemaining();
00109   if (n) {
00110     val_array = new char *[n];
00111     char *t;
00112     while (t = tok.getNext(), t != NULL) {
00113       val_array[i++] = t;
00114     }
00115     if (i < n) {
00116       Warning("There were invalid values in the definition of filter %s"
00117               "only %zu out of %zu values will be used", name, i, n);
00118     }
00119   }
00120   _setValues(i, val_array);
00121   delete[]val_array;
00122 }
00123 
00124 LogFilterString::LogFilterString(const char *name, LogField * field,
00125                                  LogFilter::Action action, LogFilter::Operator oper, size_t num_values, char **value)
00126   : LogFilter(name, field, action, oper)
00127 {
00128   _setValues(num_values, value);
00129 }
00130 
00131 LogFilterString::LogFilterString(const LogFilterString & rhs)
00132   : LogFilter(rhs.m_name, rhs.m_field, rhs.m_action, rhs.m_operator)
00133 {
00134   _setValues(rhs.m_num_values, rhs.m_value);
00135 }
00136 
00137 /*-------------------------------------------------------------------------
00138   LogFilterString::~LogFilterString
00139   -------------------------------------------------------------------------*/
00140 
00141 LogFilterString::~LogFilterString()
00142 {
00143   if (m_num_values > 0) {
00144     for (size_t i = 0; i < m_num_values; ++i) {
00145       ats_free(m_value[i]);
00146       ats_free(m_value_uppercase[i]);
00147     }
00148     delete[]m_value;
00149     delete[]m_value_uppercase;
00150     delete[]m_length;
00151   }
00152 }
00153 
00154 /*-------------------------------------------------------------------------
00155   LogFilterString::operator==
00156 
00157   This operator is not very intelligent and expects the objects being
00158   compared to have the same values specified *in the same order*.
00159   Filters with the same values specified in different order are considered
00160   to be different.
00161 
00162   -------------------------------------------------------------------------*/
00163 
00164 bool
00165 LogFilterString::operator==(LogFilterString & rhs)
00166 {
00167   if (m_type == rhs.m_type &&
00168       *m_field == *rhs.m_field &&
00169       m_action == rhs.m_action &&
00170       m_operator == rhs.m_operator &&
00171       m_num_values == rhs.m_num_values) {
00172     for (size_t i = 0; i < m_num_values; i++) {
00173       if (m_length[i] != rhs.m_length[i] ||
00174           strncmp(m_value[i], rhs.m_value[i], m_length[i])) {
00175         return false;
00176       }
00177     }
00178     return true;
00179   }
00180   return false;
00181 }
00182 
00183 /*-------------------------------------------------------------------------
00184   LogFilterString::wipe_this_entry
00185 
00186   For strings, we need to marshal the given string into a buffer so that we
00187   can compare it with the filter value.  Most strings are snall, so we'll
00188   only allocate space dynamically if the marshal_len is very large (eg,
00189   URL).
00190 
00191   The m_substr field tells us whether we can match based on substrings, or
00192   whether we should compare the entire string.
00193   -------------------------------------------------------------------------*/
00194 
00195 bool
00196 LogFilterString::wipe_this_entry(LogAccess * lad)
00197 {
00198   if (m_num_values == 0 || m_field == NULL || lad == NULL || m_action != WIPE_FIELD_VALUE) {
00199     return false;
00200   }
00201 
00202   static const unsigned BUFSIZE = 1024;
00203   char small_buf[BUFSIZE];
00204   char *big_buf = NULL;
00205   char *buf = small_buf;
00206   size_t marsh_len = m_field->marshal_len(lad);      // includes null termination
00207 
00208   if (marsh_len > BUFSIZE) {
00209     big_buf = (char *)ats_malloc(marsh_len);
00210     ink_assert(big_buf != NULL);
00211     buf = big_buf;
00212   }
00213 
00214   ink_assert(buf != NULL);
00215   m_field->marshal(lad, buf);
00216 
00217   ink_assert(buf != NULL);
00218 
00219   bool cond_satisfied = false;
00220   switch (m_operator) {
00221   case MATCH:
00222     // marsh_len is an upper bound on the length of the marshalled string
00223     // because marsh_len counts padding and the eos. So for a MATCH
00224     // operator, we use the DATA_LENGTH_LARGER length condition rather
00225     // than DATA_LENGTH_EQUAL, which we would use if we had the actual
00226     // length of the string. It is probably not worth computing the
00227     // actual length, so we just use the fact that a MATCH is not possible
00228     // when marsh_len <= (length of the filter string)
00229     //
00230     cond_satisfied = _checkConditionAndWipe(&strcmp, &buf, marsh_len, m_value, DATA_LENGTH_LARGER);
00231     break;
00232   case CASE_INSENSITIVE_MATCH:
00233     cond_satisfied = _checkConditionAndWipe(&strcasecmp, &buf, marsh_len, m_value, DATA_LENGTH_LARGER);
00234     break;
00235   case CONTAIN:
00236     cond_satisfied = _checkConditionAndWipe(&_isSubstring, &buf, marsh_len, m_value, DATA_LENGTH_LARGER);
00237     break;
00238   case CASE_INSENSITIVE_CONTAIN:
00239     for (size_t i = 0; i < marsh_len; i++) {
00240       buf[i] = ParseRules::ink_toupper(buf[i]);
00241     }
00242     cond_satisfied = _checkConditionAndWipe(&_isSubstring, &buf, marsh_len, m_value_uppercase, DATA_LENGTH_LARGER);
00243     break;
00244   default:
00245     ink_assert(!"INVALID FILTER OPERATOR");
00246   }
00247 
00248   m_field->updateField(lad, buf, strlen(buf));
00249 
00250   ats_free(big_buf);
00251   return cond_satisfied;
00252 }
00253 
00254 
00255 /*-------------------------------------------------------------------------
00256   LogFilterString::toss_this_entry
00257 
00258   For strings, we need to marshal the given string into a buffer so that we
00259   can compare it with the filter value.  Most strings are snall, so we'll
00260   only allocate space dynamically if the marshal_len is very large (eg,
00261   URL).
00262 
00263   The m_substr field tells us whether we can match based on substrings, or
00264   whether we should compare the entire string.
00265   -------------------------------------------------------------------------*/
00266 
00267 bool LogFilterString::toss_this_entry(LogAccess * lad)
00268 {
00269   if (m_num_values == 0 || m_field == NULL || lad == NULL) {
00270     return false;
00271   }
00272 
00273   static const unsigned BUFSIZE = 1024;
00274   char small_buf[BUFSIZE];
00275   char small_buf_upper[BUFSIZE];
00276   char *big_buf = NULL;
00277   char *big_buf_upper = NULL;
00278   char *buf = small_buf;
00279   char *buf_upper = small_buf_upper;
00280   size_t marsh_len = m_field->marshal_len(lad);      // includes null termination
00281 
00282   if (marsh_len > BUFSIZE) {
00283     big_buf = (char *)ats_malloc((unsigned int) marsh_len);
00284     ink_assert(big_buf != NULL);
00285     buf = big_buf;
00286   }
00287 
00288   m_field->marshal(lad, buf);
00289 
00290   bool
00291     cond_satisfied = false;
00292   switch (m_operator) {
00293   case MATCH:
00294     // marsh_len is an upper bound on the length of the marshalled string
00295     // because marsh_len counts padding and the eos. So for a MATCH
00296     // operator, we use the DATA_LENGTH_LARGER length condition rather
00297     // than DATA_LENGTH_EQUAL, which we would use if we had the actual
00298     // length of the string. It is probably not worth computing the
00299     // actual length, so we just use the fact that a MATCH is not possible
00300     // when marsh_len <= (length of the filter string)
00301     //
00302     cond_satisfied = _checkCondition(&strcmp, buf, marsh_len, m_value, DATA_LENGTH_LARGER);
00303     break;
00304   case CASE_INSENSITIVE_MATCH:
00305     cond_satisfied = _checkCondition(&strcasecmp, buf, marsh_len, m_value, DATA_LENGTH_LARGER);
00306     break;
00307   case CONTAIN:
00308     cond_satisfied = _checkCondition(&_isSubstring, buf, marsh_len, m_value, DATA_LENGTH_LARGER);
00309     break;
00310   case CASE_INSENSITIVE_CONTAIN:
00311     {
00312       if (big_buf) {
00313         big_buf_upper = (char *)ats_malloc((unsigned int) marsh_len);
00314         buf_upper = big_buf_upper;
00315       } else {
00316           buf = small_buf; // make clang happy
00317       }
00318       for (size_t i = 0; i < marsh_len; i++) {
00319         buf_upper[i] = ParseRules::ink_toupper(buf[i]);
00320       }
00321       cond_satisfied = _checkCondition(&_isSubstring, buf_upper, marsh_len, m_value_uppercase, DATA_LENGTH_LARGER);
00322       break;
00323     }
00324   default:
00325     ink_assert(!"INVALID FILTER OPERATOR");
00326   }
00327 
00328   ats_free(big_buf);
00329   ats_free(big_buf_upper);
00330 
00331   return ((m_action == REJECT && cond_satisfied) || (m_action == ACCEPT && !cond_satisfied));
00332 }
00333 
00334 /*-------------------------------------------------------------------------
00335   LogFilterString::display
00336   -------------------------------------------------------------------------*/
00337 
00338 void
00339 LogFilterString::display(FILE * fd)
00340 {
00341   ink_assert(fd != NULL);
00342   if (m_num_values == 0) {
00343     fprintf(fd, "Filter \"%s\" is inactive, no values specified\n", m_name);
00344   } else {
00345     fprintf(fd, "Filter \"%s\" %sS records if %s %s ", m_name,
00346             ACTION_NAME[m_action], m_field->symbol(), OPERATOR_NAME[m_operator]);
00347     fprintf(fd, "%s", m_value[0]);
00348     for (size_t i = 1; i < m_num_values; ++i) {
00349       fprintf(fd, ", %s", m_value[i]);
00350     }
00351     fprintf(fd, "\n");
00352   }
00353 }
00354 
00355 void
00356 LogFilterString::display_as_XML(FILE * fd)
00357 {
00358   ink_assert(fd != NULL);
00359   fprintf(fd,
00360           "<LogFilter>\n"
00361           "  <Name      = \"%s\"/>\n"
00362           "  <Action    = \"%s\"/>\n"
00363           "  <Condition = \"%s %s ", m_name, ACTION_NAME[m_action], m_field->symbol(), OPERATOR_NAME[m_operator]);
00364 
00365   if (m_num_values == 0) {
00366     fprintf(fd, "<no values>\"\n");
00367   } else {
00368     fprintf(fd, "%s", m_value[0]);
00369     for (size_t i = 1; i < m_num_values; ++i) {
00370       fprintf(fd, ", %s", m_value[i]);
00371     }
00372     fprintf(fd, "\"/>\n");
00373   }
00374   fprintf(fd, "</LogFilter>\n");
00375 }
00376 
00377 /*-------------------------------------------------------------------------
00378   LogFilterInt::LogFilterInt
00379   -------------------------------------------------------------------------*/
00380 
00381 void
00382 LogFilterInt::_setValues(size_t n, int64_t *value)
00383 {
00384   m_type = INT_FILTER;
00385   m_num_values = n;
00386   if (n) {
00387     m_value = new int64_t[n];
00388     memcpy(m_value, value, n * sizeof(int64_t));
00389   }
00390 }
00391 
00392 // TODO: ival should be int64_t
00393 int
00394 LogFilterInt::_convertStringToInt(char *value, int64_t *ival, LogFieldAliasMap * map)
00395 {
00396   size_t i, l = strlen(value);
00397   for (i = 0; i < l && ParseRules::is_digit(value[i]); i++);
00398 
00399   if (i < l) {
00400     // not all characters of value are digits, assume that
00401     // value is an alias and try to get the actual integer value
00402     // from the log field alias map if field has one
00403     //
00404     if (map == NULL || map->asInt(value, ival) != LogFieldAliasMap::ALL_OK) {
00405       return -1;                // error
00406     };
00407   } else {
00408     // all characters of value are digits, simply convert
00409     // the string to int
00410     //
00411     *ival = ink_atoui(value);
00412   }
00413   return 0;                     // all OK
00414 }
00415 
00416 LogFilterInt::LogFilterInt(const char *name, LogField * field,
00417                            LogFilter::Action action, LogFilter::Operator oper, int64_t value)
00418  : LogFilter(name, field, action, oper)
00419 {
00420   int64_t v[1];
00421   v[0] = value;
00422   _setValues(1, v);
00423 }
00424 
00425 LogFilterInt::LogFilterInt(const char *name, LogField * field,
00426                            LogFilter::Action action, LogFilter::Operator oper, size_t num_values, int64_t *value)
00427   : LogFilter(name, field, action, oper)
00428 {
00429   _setValues(num_values, value);
00430 }
00431 
00432 LogFilterInt::LogFilterInt(const char *name, LogField * field,
00433                            LogFilter::Action action, LogFilter::Operator oper, char *values)
00434   : LogFilter(name, field, action, oper)
00435 {
00436   // parse the comma-separated list of values and construct array
00437   //
00438   int64_t *val_array = 0;
00439   size_t i = 0;
00440   SimpleTokenizer tok(values, ',');
00441   size_t n = tok.getNumTokensRemaining();
00442 
00443   if (n) {
00444     val_array = new int64_t[n];
00445     char *t;
00446     while (t = tok.getNext(), t != NULL) {
00447       int64_t ival;
00448       if (!_convertStringToInt(t, &ival, field->map())) {
00449         // conversion was successful, add entry to array
00450         //
00451         val_array[i++] = ival;
00452       }
00453     }
00454     if (i < n) {
00455       Warning("There were invalid values in the definition of filter %s"
00456               " only %zu out of %zu values will be used.", name, i, n);
00457     }
00458   } else {
00459     Warning("No values in the definition of filter %s.", name);
00460   }
00461 
00462   _setValues(i, val_array);
00463 
00464   if (n) {
00465     delete[]val_array;
00466   }
00467 }
00468 
00469 LogFilterInt::LogFilterInt(const LogFilterInt & rhs)
00470   :
00471 LogFilter(rhs.m_name, rhs.m_field, rhs.m_action, rhs.m_operator)
00472 {
00473   _setValues(rhs.m_num_values, rhs.m_value);
00474 }
00475 
00476 /*-------------------------------------------------------------------------
00477   LogFilterInt::~LogFilterInt
00478   -------------------------------------------------------------------------*/
00479 
00480 LogFilterInt::~LogFilterInt()
00481 {
00482   if (m_num_values > 0) {
00483     delete[]m_value;
00484   }
00485 }
00486 
00487 /*-------------------------------------------------------------------------
00488   LogFilterInt::operator==
00489 
00490   This operator is not very intelligent and expects the objects being
00491   compared to have the same values specified *in the same order*.
00492   Filters with the same values specified in different order are considered
00493   to be different.
00494 
00495   -------------------------------------------------------------------------*/
00496 
00497 bool LogFilterInt::operator==(LogFilterInt & rhs)
00498 {
00499   if (m_type == rhs.m_type &&
00500       * m_field == * rhs.m_field &&
00501       m_action == rhs.m_action &&
00502       m_operator == rhs.m_operator &&
00503       m_num_values == rhs.m_num_values) {
00504     for (size_t i = 0; i < m_num_values; i++) {
00505       if (m_value[i] != rhs.m_value[i]) {
00506         return false;
00507       }
00508     }
00509     return true;
00510   }
00511   return false;
00512 }
00513 
00514 /*-------------------------------------------------------------------------
00515   LogFilterInt::wipe_this_entry
00516   -------------------------------------------------------------------------*/
00517 
00518 bool
00519 LogFilterInt::wipe_this_entry(LogAccess * lad)
00520 {
00521   if (m_num_values == 0 || m_field == NULL || lad == NULL || m_action != WIPE_FIELD_VALUE) {
00522     return false;
00523   }
00524 
00525   bool cond_satisfied = false;
00526   int64_t value;
00527 
00528   m_field->marshal(lad, (char *) &value);
00529   // This used to do an ntohl() on value, but that breaks various filters.
00530   // Long term we should move IPs to their own log type.
00531 
00532   // we don't use m_operator because we consider all operators to be
00533   // equivalent to "MATCH" for an integer field
00534   //
00535 
00536   // most common case is single value, speed it up a little bit by unrolling
00537   //
00538   if (m_num_values == 1) {
00539     cond_satisfied = (value == *m_value);
00540   } else {
00541     for (size_t i = 0; i < m_num_values; ++i) {
00542       if (value == m_value[i]) {
00543         cond_satisfied = true;
00544         break;
00545       }
00546     }
00547   }
00548 
00549   return cond_satisfied;
00550 }
00551 
00552 /*-------------------------------------------------------------------------
00553   LogFilterInt::toss_this_entry
00554   -------------------------------------------------------------------------*/
00555 
00556 bool LogFilterInt::toss_this_entry(LogAccess * lad)
00557 {
00558   if (m_num_values == 0 || m_field == NULL || lad == NULL) {
00559     return false;
00560   }
00561 
00562   bool cond_satisfied = false;
00563   int64_t value;
00564 
00565   m_field->marshal(lad, (char *) &value);
00566   // This used to do an ntohl() on value, but that breaks various filters.
00567   // Long term we should move IPs to their own log type.
00568 
00569   // we don't use m_operator because we consider all operators to be
00570   // equivalent to "MATCH" for an integer field
00571   //
00572 
00573   // most common case is single value, speed it up a little bit by unrolling
00574   //
00575   if (m_num_values == 1) {
00576     cond_satisfied = (value == *m_value);
00577   } else {
00578     for (size_t i = 0; i < m_num_values; ++i) {
00579       if (value == m_value[i]) {
00580         cond_satisfied = true;
00581         break;
00582       }
00583     }
00584   }
00585 
00586   return (m_action == REJECT && cond_satisfied) || (m_action == ACCEPT && !cond_satisfied);
00587 }
00588 
00589 /*-------------------------------------------------------------------------
00590   LogFilterInt::display
00591   -------------------------------------------------------------------------*/
00592 
00593 void
00594 LogFilterInt::display(FILE * fd)
00595 {
00596   ink_assert(fd != NULL);
00597   if (m_num_values == 0) {
00598     fprintf(fd, "Filter \"%s\" is inactive, no values specified\n", m_name);
00599   } else {
00600     fprintf(fd, "Filter \"%s\" %sS records if %s %s ", m_name,
00601             ACTION_NAME[m_action], m_field->symbol(), OPERATOR_NAME[m_operator]);
00602     fprintf(fd, "%" PRId64 "", m_value[0]);
00603     for (size_t i = 1; i < m_num_values; ++i) {
00604       fprintf(fd, ", %" PRId64 "", m_value[i]);
00605     }
00606     fprintf(fd, "\n");
00607   }
00608 }
00609 
00610 void
00611 LogFilterInt::display_as_XML(FILE * fd)
00612 {
00613   ink_assert(fd != NULL);
00614   fprintf(fd,
00615           "<LogFilter>\n"
00616           "  <Name      = \"%s\"/>\n"
00617           "  <Action    = \"%s\"/>\n"
00618           "  <Condition = \"%s %s ", m_name, ACTION_NAME[m_action], m_field->symbol(), OPERATOR_NAME[m_operator]);
00619 
00620   if (m_num_values == 0) {
00621     fprintf(fd, "<no values>\"\n");
00622   } else {
00623     fprintf(fd, "%" PRId64 "", m_value[0]);
00624     for (size_t i = 1; i < m_num_values; ++i) {
00625       fprintf(fd, ", %" PRId64 "", m_value[i]);
00626     }
00627     fprintf(fd, "\"/>\n");
00628   }
00629   fprintf(fd, "</LogFilter>\n");
00630 }
00631 
00632 /*-------------------------------------------------------------------------
00633   LogFilterIP::LogFilterIP
00634   -------------------------------------------------------------------------*/
00635 LogFilterIP::LogFilterIP(const char *name, LogField * field,
00636                            LogFilter::Action action, LogFilter::Operator oper, IpAddr value)
00637   : LogFilter(name, field, action, oper)
00638 {
00639   m_map.mark(value,value);
00640   this->init();
00641 }
00642  
00643 LogFilterIP::LogFilterIP(const char *name, LogField * field,
00644                            LogFilter::Action action, LogFilter::Operator oper, size_t num_values, IpAddr* value)
00645   : LogFilter(name, field, action, oper)
00646 {
00647   for ( IpAddr* limit = value + num_values ; value != limit ; ++value )
00648     m_map.mark(*value,*value);
00649   this->init();
00650 }
00651 
00652 LogFilterIP::LogFilterIP(const char *name, LogField * field,
00653                            LogFilter::Action action, LogFilter::Operator oper, char *values)
00654   : LogFilter(name, field, action, oper)
00655 {
00656   // parse the comma-separated list of values and construct array
00657   //
00658   size_t i = 0;
00659   SimpleTokenizer tok(values, ',');
00660   size_t n = tok.getNumTokensRemaining();
00661   char* t; // temp token pointer.
00662 
00663   if (n) {
00664     while (t = tok.getNext(), t != NULL) {
00665       IpAddr min, max;
00666       char* x = strchr(t, '-');
00667       if (x) *x++ = 0;
00668       if (0 == min.load(t)) {
00669         if (x) {
00670           if (0 != max.load(x)) {
00671             Warning("LogFilterIP Configuration: '%s-%s' looks like a range but the second address was ill formed", t,x);
00672             continue;
00673           }
00674         } else {
00675           max = min;
00676         }
00677         m_map.mark(min,max);
00678         ++i;
00679       } else {
00680         Warning("LogFilterIP Configuration:  '%s' is ill formed", t);
00681       }
00682     }
00683     if (i < n) {
00684       Warning("There were invalid IP values in the definition of filter %s"
00685               " only %zu out of %zu values will be used.", name, i, n);
00686     }
00687   } else {
00688     Warning("No values in the definition of filter %s.", name);
00689   }
00690   this->init();
00691 }
00692 
00693 LogFilterIP::LogFilterIP(const LogFilterIP & rhs)
00694   : LogFilter(rhs.m_name, rhs.m_field, rhs.m_action, rhs.m_operator)
00695 {
00696   for ( IpMap::iterator spot(rhs.m_map.begin()), limit(rhs.m_map.end()) ; spot != limit ; ++spot ) {
00697     m_map.mark(spot->min(), spot->max(), spot->data());
00698   }
00699   this->init();
00700 }
00701 
00702 void
00703 LogFilterIP::init()
00704 {
00705   m_type = IP_FILTER;
00706   m_num_values = m_map.getCount();
00707 }
00708 
00709 /*-------------------------------------------------------------------------
00710   LogFilterIP::~LogFilterIP
00711   -------------------------------------------------------------------------*/
00712 
00713 LogFilterIP::~LogFilterIP()
00714 {
00715 }   
00716     
00717 /*-------------------------------------------------------------------------
00718   LogFilterIP::operator==
00719 
00720   This operator is not very intelligent and expects the objects being
00721   compared to have the same values specified *in the same order*.
00722   Filters with the same values specified in different order are considered
00723   to be different.
00724 
00725   -------------------------------------------------------------------------*/
00726 
00727 bool
00728 LogFilterIP::operator==(LogFilterIP & rhs)
00729 {
00730   if (m_type == rhs.m_type &&
00731       *m_field == *rhs.m_field &&
00732       m_action == rhs.m_action &&
00733       m_operator == rhs.m_operator &&
00734       m_num_values == rhs.m_num_values) {
00735     
00736     IpMap::iterator left_spot(m_map.begin());
00737     IpMap::iterator left_limit(m_map.end());
00738     IpMap::iterator right_spot(rhs.m_map.begin());
00739     IpMap::iterator right_limit(rhs.m_map.end());
00740 
00741     while (left_spot != left_limit && right_spot != right_limit) {
00742       if (!ats_ip_addr_eq(left_spot->min(), right_spot->min()) ||
00743           !ats_ip_addr_eq(left_spot->max(), right_spot->max()))
00744         break;
00745       ++left_spot;
00746       ++right_spot;
00747     }
00748 
00749     return left_spot == left_limit && right_spot == right_limit;
00750   }
00751   return false;
00752 }
00753 
00754 /*-------------------------------------------------------------------------
00755   LogFilterIP::toss_this_entry
00756   -------------------------------------------------------------------------*/
00757 
00758 bool
00759 LogFilterIP::is_match(LogAccess* lad)
00760 {
00761   bool zret = false;
00762 
00763   if (m_field && lad) {
00764     LogFieldIpStorage value;
00765     m_field->marshal(lad, reinterpret_cast<char *>(&value));
00766     // This is bad, we abuse the fact that the initial layout of LogFieldIpStorage and IpAddr
00767     // are identical. We should look at converting the log stuff to use IpAddr directly.
00768     zret = m_map.contains(reinterpret_cast<IpAddr&>(value));
00769   }
00770 
00771   return zret;
00772 }
00773 
00774 bool 
00775 LogFilterIP::toss_this_entry(LogAccess* lad)
00776 {
00777   bool cond_satisfied = this->is_match(lad);
00778   return (m_action == REJECT && cond_satisfied) || (m_action == ACCEPT && !cond_satisfied);
00779 }
00780 
00781 bool
00782 LogFilterIP::wipe_this_entry(LogAccess*)
00783 {
00784 # if 0
00785   bool zret = WIPE_FIELD_VALUE == m_action && this->is_match(lad);
00786   if (zret) {
00787     // set to ADDR_ANY.
00788   }
00789   return zret;
00790 # else
00791   return false;
00792 # endif
00793 }
00794 
00795 /*-------------------------------------------------------------------------
00796   LogFilterIP::display
00797   -------------------------------------------------------------------------*/
00798 
00799 void
00800 LogFilterIP::displayRange(FILE* fd, IpMap::iterator const& iter)
00801 {
00802   ip_text_buffer ipb;
00803 
00804   fprintf(fd, "%s", ats_ip_ntop(iter->min(), ipb, sizeof(ipb)));
00805 
00806   if (!ats_ip_addr_eq(iter->min(), iter->max()))
00807     fprintf(fd, "-%s", ats_ip_ntop(iter->max(), ipb, sizeof(ipb)));
00808 }
00809 
00810 void
00811 LogFilterIP::displayRanges(FILE * fd)
00812 {
00813   IpMap::iterator spot(m_map.begin()), limit(m_map.end());
00814   ink_assert(spot != limit);
00815 
00816   this->displayRange(fd, spot);
00817   for ( ++spot ; spot != limit ; ++spot ) {
00818     for (size_t i = 1; i < m_num_values; ++i) {
00819       fprintf(fd, ",");
00820       this->displayRange(fd, spot);
00821     }
00822   }
00823 }
00824 
00825 void
00826 LogFilterIP::display(FILE* fd)
00827 {
00828   ink_assert(fd != NULL);
00829 
00830   if (0 == m_map.getCount()) {
00831     fprintf(fd, "Filter \"%s\" is inactive, no values specified\n", m_name);
00832   } else {
00833     fprintf(fd, "Filter \"%s\" %sS records if %s %s ", m_name, ACTION_NAME[m_action], m_field->symbol(), OPERATOR_NAME[m_operator]);
00834     this->displayRanges(fd);
00835     fprintf(fd, "\n");
00836   }
00837 }
00838 
00839  
00840 void 
00841 LogFilterIP::display_as_XML(FILE * fd)
00842 {  
00843   ink_assert(fd != NULL);
00844   fprintf(fd,
00845           "<LogFilter>\n"
00846           "  <Name      = \"%s\"/>\n" 
00847           "  <Action    = \"%s\"/>\n"
00848           "  <Condition = \"%s %s ", m_name, ACTION_NAME[m_action], m_field->symbol(), OPERATOR_NAME[m_operator]);
00849 
00850   if (m_map.getCount() == 0) {
00851     fprintf(fd, "<no values>");  
00852   } else {
00853     this->displayRanges(fd);
00854   }
00855   fprintf(fd, "\"/>\n");
00856   fprintf(fd, "</LogFilter>\n");
00857 }
00858 
00859 bool
00860 filters_are_equal(LogFilter * filt1, LogFilter * filt2)
00861 {
00862   bool ret = false;
00863 
00864   // TODO: we should check name here
00865   if (filt1->type() == filt2->type()) {
00866     if (filt1->type() == LogFilter::INT_FILTER) {
00867       Debug("log-filter-compare", "int compare");
00868       ret = (*((LogFilterInt *) filt1) == *((LogFilterInt *) filt2));
00869     } else if (filt1->type() == LogFilter::IP_FILTER) {
00870       ret = (*((LogFilterIP *) filt1) == *((LogFilterIP *) filt2));
00871     } else if (filt1->type() == LogFilter::STRING_FILTER) {
00872       ret = (*((LogFilterString *) filt1) == *((LogFilterString *) filt2));
00873     } else {
00874       ink_assert(!"invalid filter type");
00875     }
00876   } else {
00877     Debug("log-filter-compare", "type diff");
00878   }
00879   return ret;
00880 }
00881 
00882 /*-------------------------------------------------------------------------
00883   LogFilterList
00884 
00885   It is ASSUMED that each element on this list has been allocated from the
00886   heap with "new" and that each element is on at most ONE list.  To enforce
00887   this, we allow for copies to be made by the system, which is why the
00888   add() function is overloaded for each sub-type of LogFilter.
00889   -------------------------------------------------------------------------*/
00890 
00891 LogFilterList::LogFilterList():m_does_conjunction(true)
00892 {
00893 }
00894 
00895 /*-------------------------------------------------------------------------
00896   -------------------------------------------------------------------------*/
00897 
00898 LogFilterList::~LogFilterList()
00899 {
00900   clear();
00901 }
00902 
00903 /*-------------------------------------------------------------------------
00904   -------------------------------------------------------------------------*/
00905 
00906 bool LogFilterList::operator==(LogFilterList & rhs)
00907 {
00908   if (m_does_conjunction == rhs.does_conjunction()) {
00909     LogFilter *f = first();
00910     LogFilter *rhsf = rhs.first();
00911 
00912     while (true) {
00913       if (!(f || rhsf)) {
00914         return true;
00915       } else if (!f || !rhsf) {
00916         return false;
00917       } else if (!filters_are_equal(f, rhsf)) {
00918         return false;
00919       } else {
00920         f = next(f);
00921         rhsf = rhs.next(rhsf);
00922       }
00923     }
00924   } else {
00925     return false;
00926   }
00927 }
00928 
00929 /*-------------------------------------------------------------------------
00930   -------------------------------------------------------------------------*/
00931 
00932 void
00933 LogFilterList::clear()
00934 {
00935   LogFilter *f;
00936   while ((f = m_filter_list.dequeue())) {
00937     delete f;                   // safe given the semantics stated above
00938   }
00939 }
00940 
00941 /*-------------------------------------------------------------------------
00942   -------------------------------------------------------------------------*/
00943 
00944 void
00945 LogFilterList::add(LogFilter * filter, bool copy)
00946 {
00947   ink_assert(filter != NULL);
00948   if (copy) {
00949     if (filter->type() == LogFilter::INT_FILTER) {
00950       LogFilterInt *f = new LogFilterInt(*((LogFilterInt *) filter));
00951       m_filter_list.enqueue(f);
00952     } else if (filter->type() == LogFilter::IP_FILTER) {   
00953       LogFilterIP *f = new LogFilterIP(*((LogFilterIP *) filter));
00954       m_filter_list.enqueue(f);
00955     } else {
00956       LogFilterString *f = new LogFilterString(*((LogFilterString *) filter));
00957       m_filter_list.enqueue(f);
00958     }
00959   } else {
00960     m_filter_list.enqueue(filter);
00961   }
00962 }
00963 
00964 /*-------------------------------------------------------------------------
00965   -------------------------------------------------------------------------*/
00966 
00967 bool
00968 LogFilterList::wipe_this_entry(LogAccess * lad)
00969 {
00970   bool wipeFlag = false;
00971     for (LogFilter * f = first(); f; f = next(f)) {
00972       if (f->wipe_this_entry(lad)) {
00973         wipeFlag = true;
00974       }
00975     }
00976     return wipeFlag;
00977 }
00978 
00979 
00980 /*-------------------------------------------------------------------------
00981   -------------------------------------------------------------------------*/
00982 
00983 bool LogFilterList::toss_this_entry(LogAccess * lad)
00984 {
00985   if (m_does_conjunction) {
00986     // toss if any filter rejects the entry (all filters should accept)
00987     //
00988     for (LogFilter * f = first(); f; f = next(f)) {
00989       if (f->toss_this_entry(lad)) {
00990         return true;
00991       }
00992     }
00993     return false;
00994   } else {
00995     // toss if all filters reject the entry (any filter accepts)
00996     //
00997     for (LogFilter * f = first(); f; f = next(f)) {
00998       if (!f->toss_this_entry(lad)) {
00999         return false;
01000       }
01001     }
01002     return true;
01003   }
01004 }
01005 
01006 /*-------------------------------------------------------------------------
01007   -------------------------------------------------------------------------*/
01008 
01009 LogFilter *
01010 LogFilterList::find_by_name(char *name)
01011 {
01012   for (LogFilter * f = first(); f; f = next(f)) {
01013     if (strcmp(f->name(), name) == 0) {
01014       return f;
01015     }
01016   }
01017   return NULL;
01018 }
01019 
01020 
01021 /*-------------------------------------------------------------------------
01022   -------------------------------------------------------------------------*/
01023 
01024 unsigned
01025 LogFilterList::count()
01026 {
01027   unsigned cnt = 0;
01028 
01029   for (LogFilter * f = first(); f; f = next(f)) {
01030     cnt++;
01031   }
01032   return cnt;
01033 }
01034 
01035 void
01036 LogFilterList::display(FILE * fd)
01037 {
01038   for (LogFilter * f = first(); f; f = next(f)) {
01039     f->display(fd);
01040   }
01041 }
01042 
01043 void
01044 LogFilterList::display_as_XML(FILE * fd)
01045 {
01046   for (LogFilter * f = first(); f; f = next(f)) {
01047     f->display_as_XML(fd);
01048   }
01049 }

Generated by  doxygen 1.7.1