* basic snmp packets assembly/disassembly and send/receive functions
*
* Copyright (c) Roman Festchook <roma at polesye dot net>
- * Jan Rafaj <jr-aputils at cedric dot unob dot cz>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License Version 2 from
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include <signal.h>
-#include <setjmp.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "ap-utils.h"
-sigjmp_buf position;
-
extern char *community;
extern short ap_type;
-extern int sockfd;
extern struct in_addr ap_ip;
-int snmp_retries = 5, retries;
-char *buf = NULL;
+int sockfd = 0, snmp_quit_by_keypress = 0;
-static void alarm_handler()
+void close_sockfd()
{
- retries--;
- siglongjmp(position, 1);
+ if (sockfd)
+ close(sockfd);
+}
+
+int open_sockfd()
+{
+ struct sockaddr_in client;
+
+ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+ return -1;
+
+ memset(&client, 0, sizeof client);
+ client.sin_family = AF_INET;
+ client.sin_port = INADDR_ANY;
+ client.sin_addr.s_addr = INADDR_ANY;
+
+ if (bind(sockfd, (struct sockaddr *) &client, SIZE) == -1)
+ return -1;
+
+ return 0;
+}
+
+int reopen_sockfd()
+{
+ close_sockfd();
+ return (open_sockfd());
}
/*
int snmp(varbind * varbindlist, int num, int type)
{
- unsigned char message[1024], *start;
+ static char buf[1024];
+ unsigned char *start;
unsigned int num_reply;
- int len;
+ int len = 0, tries = 5;
struct sockaddr_in server;
+ struct timeval timeout;
+ fd_set rds;
if (num == 0)
return 1;
+ /*
+ * Flush sockfd by reopening. This prevents various 'something received/
+ * available on sockfd prior snmp() call' desync problems.
+ */
+ if (reopen_sockfd() == -1)
+ return 0;
+
memset(&server, 0, sizeof server);
server.sin_family = AF_INET;
server.sin_port = htons(161);
server.sin_addr.s_addr = ap_ip.s_addr;
- signal(SIGALRM, alarm_handler);
- retries = snmp_retries;
- sigsetjmp(position, 1);
- if (!retries) {
- return 0;
- }
+ while (tries--) {
+ len = ber(buf, varbindlist, num, type);
+ if (sendto(sockfd, buf, len, 0, (struct sockaddr *) &server, SIZE)
+ == -1) {
+ return 0;
+ }
- alarm(1);
- len = ber(message, varbindlist, num, type);
- if (sendto(sockfd, message, len, 0, (struct sockaddr *) &server, SIZE)
- == -1) {
- alarm(0);
- return 0;
- }
- if ((len = recv(sockfd, message, 1024, 0)) == -1) {
- alarm(0);
- return 0;
+ FD_ZERO(&rds);
+ FD_SET(sockfd, &rds);
+ timeout.tv_sec = 1;
+ timeout.tv_usec = 0;
+
+ if (select(sockfd + 1, &rds, NULL, NULL, &timeout) == -1)
+ return 0;
+
+ if (FD_ISSET(sockfd, &rds)) {
+ if ((len = recv(sockfd, buf, sizeof buf, 0)) <= 0)
+ return 0;
+ else
+ break;
+ }
+
+ /* timeout => next try, as long as no key has been pressed */
+
+ /*
+ * Allow for quick 'last resort' escape using q/Q. Note:
+ * we may not use one select() for checking both fd 0 and sockfd, since
+ * something may appear on sockfd later than key has been pressed =>
+ * give gratuitous 1sec delay for response arrival to sockfd, and THEN
+ * just poll for anything on fd 0.
+ */
+ if (snmp_quit_by_keypress && type == GET) {
+ FD_ZERO(&rds);
+ FD_SET(0, &rds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ if (select(1, &rds, NULL, NULL, &timeout) == -1)
+ return 0;
+
+ if (FD_ISSET(0, &rds))
+ return 0;
+ }
}
- alarm(0);
- if (buf)
- free(buf);
- buf = (char *) malloc(len);
- memcpy(buf, message, len);
+ if (!tries)
+ return 0;
start = buf;
num_reply = 0;