zeroSquitto – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /*************************************************************************/
2 /* Logging server - ZeroMQ and Mosquitto Publisher-Subscriber Project */
3 /*************************************************************************/
4  
5 #include "constants.h"
6 #include <arpa/inet.h>
7 #include <fcntl.h>
8 #include <getopt.h>
9 #include <netdb.h>
10 #include <netinet/in.h>
11 #include <pthread.h>
12 #include <signal.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <sys/socket.h>
17 #include <sys/types.h>
18 #include <syslog.h>
19 #include <termios.h>
20 #include <unistd.h>
21  
22 // Used for program termination.
23 static volatile int run = 1;
24  
25 // Stucture passed as argument to threads.
26 typedef struct {
27 char *name;
28 char *address;
29 int port;
30 } Targs;
31  
32 void printUsage(char **argv) {
33 printf("Usage: %s [OPTIONS]\n", argv[0]);
34 printf("\t-n <name>\t\tname to log under\n");
35 printf("\t-a <address>\t\taddress to listen on\n");
36 printf("\t-p <port>\t\tport to listen on\n");
37  
38 printf("\n");
39 }
40  
41 // Handles SIGHUP and SIGINT (Ctrl + C)
42 void trap(int signal) {
43 printf("[✓] Received interrupt, terminating...\n");
44 switch (signal) {
45 case SIGHUP:
46 case SIGINT:
47 run = 0;
48 break;
49 }
50 }
51  
52 void *serveLog(void *argsThread) {
53 // Function arguments.
54 Targs *args = (Targs *)argsThread;
55 int serverSocket, clientSocket;
56 char *data = (char *)calloc(LOG_MAX_RECV_BYTES, sizeof(char));
57 struct sockaddr_in serverSockAddr;
58 struct sockaddr_in clientSockAddr;
59 socklen_t clientAddrSize;
60 // To store connecting client address.
61 struct hostent *host;
62 char *hostaddrp;
63 int reuseSocket = 1;
64 int readBytes;
65  
66 // Open syslog.
67 setlogmask(LOG_UPTO(LOG_INFO));
68 openlog(args->name, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1);
69  
70 // Create socket.
71 if ((serverSocket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
72 printf("[E] Error creating socket.\n");
73 goto CLEANUP;
74 }
75  
76 // Set non-blocking socket.
77 fcntl(serverSocket, F_SETFL, O_NONBLOCK);
78  
79 // Reuse socket address.
80 setsockopt(clientSocket, SOL_SOCKET, SO_REUSEADDR, (const void *)&reuseSocket,
81 sizeof(int));
82 bzero((char *)&serverSockAddr, sizeof(serverSockAddr));
83 serverSockAddr.sin_family = AF_INET;
84 serverSockAddr.sin_addr.s_addr = inet_addr(args->address);
85 serverSockAddr.sin_port = htons(args->port);
86  
87 // Bind to socket.
88 if (bind(serverSocket, (struct sockaddr *)&serverSockAddr,
89 sizeof(serverSockAddr)) < 0) {
90 printf("[E] Error binding to the socket socket.\n");
91 goto CLEANUP;
92 }
93  
94 // Listen to the socket with a specified number of queued requests.
95 if (listen(serverSocket, LOG_SERVER_TCP_LISTEN_QUEUE) < 0) {
96 printf("[E] Error listening on socket.\n");
97 goto CLEANUP;
98 }
99  
100 printf("[✓] Listening for log messages on %s:%d.\n", args->address,
101 args->port);
102  
103 clientAddrSize = sizeof(clientSockAddr);
104 do {
105  
106 // Listen for client connections in a non-blocking fashion.
107 if ((clientSocket = accept(serverSocket, (struct sockaddr *)&clientSockAddr,
108 &clientAddrSize)) < 0) {
109 sleep(1);
110 continue;
111 }
112  
113 // Catch client address for reporting.
114 if ((host = gethostbyaddr((const char *)&clientSockAddr.sin_addr.s_addr,
115 sizeof(clientSockAddr.sin_addr.s_addr),
116 AF_INET)) == NULL ||
117 (hostaddrp = inet_ntoa(clientSockAddr.sin_addr)) == NULL) {
118 printf("[E] Error retrieving client address.\n");
119 close(clientSocket);
120 continue;
121 }
122  
123 // Read data from the client.
124 if ((readBytes = read(clientSocket, data, LOG_MAX_RECV_BYTES)) < 0) {
125 printf("[E] Error reading client data.\n");
126 close(clientSocket);
127 continue;
128 }
129  
130 // Close the client socket.
131 close(clientSocket);
132  
133 fprintf(stdout, "[✓] %s (%s) : %s\n", host->h_name, hostaddrp, data);
134 fflush(stdout);
135  
136 // Send to syslog.
137 syslog(LOG_INFO, "%s (%s) : %s", host->h_name, hostaddrp, data);
138  
139 // Clean the client receive buffer.
140 bzero(data, LOG_MAX_RECV_BYTES);
141 } while (run);
142  
143 CLEANUP:
144  
145 // Close the client socket.
146 close(clientSocket);
147  
148 // Close syslog.
149 closelog();
150  
151 // Free buffers.
152 free(data);
153  
154 // Exit context.
155 pthread_exit(NULL);
156 }
157  
158 int main(int argc, char **argv) {
159 // For terminal input supression.
160 struct termios tattr;
161 struct termios tattr_store;
162 // The thread arguments.
163 Targs *args = (Targs *)calloc(1, sizeof(Targs));
164 // The listener thread for ZeroMQ.
165 pthread_t logThread;
166 // Command-line processing.
167 const char *short_opt = "hn:a:p:";
168 struct option long_opt[] = {{"help", no_argument, NULL, 'h'},
169 {"name", required_argument, NULL, 'n'},
170 {"address", required_argument, NULL, 'a'},
171 {"port", required_argument, NULL, 'p'},
172 {NULL, 0, NULL, 0}};
173 int c;
174 int hasName, hasServer, hasPort;
175  
176 while ((c = getopt_long(argc, argv, short_opt, long_opt, NULL)) != -1)
177 switch (c) {
178 case -1:
179 case 0:
180 break;
181  
182 case 'n':
183 args->name = (char *)calloc(strlen(optarg) + 1, sizeof(char));
184 strncat(args->name, optarg, strlen(optarg));
185 ++hasName;
186 break;
187 case 'a':
188 args->address = (char *)calloc(strlen(optarg) + 1, sizeof(char));
189 strncat(args->address, optarg, strlen(optarg));
190 ++hasServer;
191 break;
192 case 'p':
193 args->port = atoi(optarg);
194 ++hasPort;
195 break;
196 case 'h':
197 printUsage(argv);
198 return -1;
199  
200 case ':':
201 case '?':
202 printf("Try `%s --help' for more information.\n", argv[0]);
203 return -1;
204 default:
205 printf("%s: invalid option -- %c\n", argv[0], c);
206 printf("Try `%s --help' for more information.\n", argv[0]);
207 return -1;
208 }
209  
210 if (hasName == 0 || hasServer == 0 || hasPort == 0) {
211 printUsage(argv);
212 return -1;
213 }
214  
215 // Suppress console input for clarity if this is a terminal.
216 if (isatty(STDIN_FILENO)) {
217 // Save the attributes and restore them on program termination.
218 tcgetattr(STDIN_FILENO, &tattr_store);
219 tcgetattr(STDIN_FILENO, &tattr);
220 tattr.c_lflag &= ~(ICANON | ECHO);
221 tcsetattr(STDIN_FILENO, TCSAFLUSH, &tattr);
222 }
223  
224 // Let there be bling!
225 printf("%s\n", LOGGING_BANNER);
226 printf("\tTip: Use Ctrl-c to end program.\n\n");
227  
228 // Bind to SIGHUP and SIGINT.
229 signal(SIGHUP, trap);
230 signal(SIGINT, trap);
231  
232 if (pthread_create(&logThread, NULL, serveLog, (void *)args))
233 printf("[E] Failed to create log thread!\n");
234  
235 // Await thread termination.
236 pthread_join(logThread, NULL);
237  
238 // Free arguments.
239 free(args);
240  
241 // If this is a terminal, restore the terminal attributes.
242 if (isatty(STDIN_FILENO))
243 tcsetattr(STDIN_FILENO, TCSANOW, &tattr_store);
244  
245 // Clean exit.
246 return 0;
247 }