X-Git-Url: https://git.decadent.org.uk/gitweb/?a=blobdiff_plain;f=lib%2Fsnmp.c;h=cab421281a14ff1414c535daa2e841435b51c6ee;hb=17cd5711411f45df26b33c51288780627b7377e2;hp=f688c55d9242a473a203cc4b39985b630ecb35de;hpb=09ed626f25fb3e7c57ad7a59e5261ea005aa498f;p=ap-utils.git diff --git a/lib/snmp.c b/lib/snmp.c index f688c55..cab4212 100644 --- a/lib/snmp.c +++ b/lib/snmp.c @@ -2,7 +2,7 @@ * snmp.c from Access Point SNMP Utils for Linux * basic snmp packets assembly/disassembly and send/receive functions * - * Copyright (c) 2002 Roman Festchook + * Copyright (c) Roman Festchook * * 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 @@ -21,31 +21,63 @@ #include #include #include -#include -#include +#include #include #include #include #include #include "ap-utils.h" -#define RETRIES 5 - -sigjmp_buf position; - extern char *community; extern short ap_type; -extern int sockfd; extern struct in_addr ap_ip; -int retries; -char *buf = NULL; -static void alarm_handler() +int sockfd = 0, snmp_quit_by_keypress = 0; + +void close_sockfd() +{ + 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() { - retries--; - siglongjmp(position, 1); + close_sockfd(); + return (open_sockfd()); } +/* +unsigned int ber_decode_uint(unsigned char *bevp, int len) +{ + unsigned int out = 0; + + while (len--) { + out = (out << 7) | (*bevp & (*bevp & 0x80 ? 0x7f : 0xff)); + bevp++; + } + + return out; +} +*/ + int ber(char *message, varbind * varbindlist, int num, int type) { @@ -130,43 +162,75 @@ int ber(char *message, varbind * varbindlist, int num, int type) 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 = 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;