1 /** @file
2     WCCP router simulation for testing.
3 
4     @section license License
5 
6     Licensed to the Apache Software Foundation (ASF) under one
7     or more contributor license agreements.  See the NOTICE file
8     distributed with this work for additional information
9     regarding copyright ownership.  The ASF licenses this file
10     to you under the Apache License, Version 2.0 (the
11     "License"); you may not use this file except in compliance
12     with the License.  You may obtain a copy of the License at
13 
14     http://www.apache.org/licenses/LICENSE-2.0
15 
16     Unless required by applicable law or agreed to in writing, software
17     distributed under the License is distributed on an "AS IS" BASIS,
18     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19     See the License for the specific language governing permissions and
20     limitations under the License.
21  */
22 
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <stdarg.h>
26 #include <memory.h>
27 #include <strings.h>
28 
29 #include <getopt.h>
30 
31 #include "Wccp.h"
32 
33 #include <sys/socket.h>
34 #include <netinet/in.h>
35 #include <arpa/inet.h>
36 
37 #include <poll.h>
38 
39 static char const USAGE_TEXT[] = "%s\n"
40                                  "--address IP address to bind.\n"
41                                  "--help Print usage and exit.\n";
42 
43 static bool Ready = true;
44 
45 inline void
Error(char const * fmt,...)46 Error(char const *fmt, ...)
47 {
48   va_list args;
49   va_start(args, fmt);
50   vfprintf(stderr, fmt, args);
51   va_end(args);
52 
53   Ready = false;
54 }
55 
56 int
main(int argc,char ** argv)57 main(int argc, char **argv)
58 {
59   wccp::Router wcp;
60 
61   // Reading stdin support.
62   size_t in_size = 200;
63   char *in_buff  = 0;
64   ssize_t in_count;
65 
66   // getopt return values. Selected to avoid collisions with
67   // short arguments.
68   static int const OPT_ADDRESS = 257; ///< Bind to IP address option.
69   static int const OPT_HELP    = 258; ///< Print help message.
70   static int const OPT_MD5     = 259; ///< MD5 key.
71 
72   static option OPTIONS[] = {
73     {"address", 1, 0, OPT_ADDRESS}, {"md5", 1, 0, OPT_MD5}, {"help", 0, 0, OPT_HELP}, {0, 0, 0, 0} // required terminator.
74   };
75 
76   in_addr ip_addr = {INADDR_ANY};
77 
78   int zret; // getopt return.
79   int zidx; // option index.
80   bool fail            = false;
81   char const *FAIL_MSG = "";
82 
83   while (-1 != (zret = getopt_long_only(argc, argv, "", OPTIONS, &zidx))) {
84     switch (zret) {
85     case OPT_HELP:
86       FAIL_MSG = "Usage:";
87       fail     = true;
88       break;
89     case '?':
90       FAIL_MSG = "Invalid option specified.";
91       fail     = true;
92       break;
93     case OPT_ADDRESS:
94       if (0 == inet_aton(optarg, &ip_addr)) {
95         FAIL_MSG = "Invalid IP address specified for client.";
96         fail     = true;
97       }
98       break;
99     case OPT_MD5:
100       wcp.useMD5Security(optarg);
101       break;
102     }
103   }
104 
105   if (fail) {
106     printf(USAGE_TEXT, FAIL_MSG);
107     return 1;
108   }
109 
110   if (!Ready)
111     return 4;
112 
113   if (0 > wcp.open(ip_addr.s_addr)) {
114     fprintf(stderr, "Failed to open or bind socket.\n");
115     return 2;
116   }
117 
118   static int const POLL_FD_COUNT = 2;
119   pollfd pfa[POLL_FD_COUNT];
120 
121   // Poll on STDIN and the socket.
122   pfa[0].fd     = STDIN_FILENO;
123   pfa[0].events = POLLIN;
124 
125   pfa[1].fd     = wcp.getSocket();
126   pfa[1].events = POLLIN;
127 
128   while (true) {
129     int n = poll(pfa, POLL_FD_COUNT, wccp::TIME_UNIT * 1000);
130     if (n < 0) { // error
131       perror("General polling failure");
132       return 5;
133     } else if (n > 0) { // things of interest happened
134       if (pfa[1].revents) {
135         if (pfa[1].revents & POLLIN) {
136           wcp.handleMessage();
137           // wcp.sendPendingMessages();
138         } else {
139           fprintf(stderr, "Socket failure.\n");
140           return 6;
141         }
142       }
143       if (pfa[0].revents) {
144         if (pfa[0].revents & POLLIN) {
145           in_count = getline(&in_buff, &in_size, stdin);
146           fprintf(stderr, "Terminated from console.\n");
147           return 0;
148         }
149       }
150     } else { // timeout
151       // wcp.sendPendingMessages();
152     }
153   }
154 }
155