00001 #include <net-snmp/net-snmp-config.h>
00002
00003 #include <stdio.h>
00004 #include <sys/types.h>
00005 #include <errno.h>
00006
00007 #if HAVE_STRING_H
00008 #include <string.h>
00009 #else
00010 #include <strings.h>
00011 #endif
00012 #if HAVE_STDLIB_H
00013 #include <stdlib.h>
00014 #endif
00015 #if HAVE_UNISTD_H
00016 #include <unistd.h>
00017 #endif
00018 #if HAVE_SYS_SOCKET_H
00019 #include <sys/socket.h>
00020 #endif
00021 #if HAVE_NETINET_IN_H
00022 #include <netinet/in.h>
00023 #endif
00024 #if HAVE_ARPA_INET_H
00025 #include <arpa/inet.h>
00026 #endif
00027 #if HAVE_FCNTL_H
00028 #include <fcntl.h>
00029 #endif
00030
00031 #if HAVE_WINSOCK_H
00032 #include <winsock2.h>
00033 #include <ws2tcpip.h>
00034 #endif
00035
00036 #if HAVE_DMALLOC_H
00037 #include <dmalloc.h>
00038 #endif
00039
00040 #include <net-snmp/types.h>
00041 #include <net-snmp/output_api.h>
00042
00043 #include <net-snmp/library/snmp_transport.h>
00044 #include <net-snmp/library/snmpUDPDomain.h>
00045 #include <net-snmp/library/snmpTCPDomain.h>
00046
00047
00048 typedef struct netsnmp_udp_addr_pair_s {
00049 struct sockaddr_in remote_addr;
00050 struct in_addr local_addr;
00051 } netsnmp_udp_addr_pair;
00052
00053 oid netsnmp_snmpTCPDomain[] = { TRANSPORT_DOMAIN_TCP_IP };
00054 static netsnmp_tdomain tcpDomain;
00055
00056
00057
00058
00059
00060
00061 static char *
00062 netsnmp_tcp_fmtaddr(netsnmp_transport *t, void *data, int len)
00063 {
00064 netsnmp_udp_addr_pair *addr_pair = NULL;
00065
00066 if (data != NULL && len == sizeof(netsnmp_udp_addr_pair)) {
00067 addr_pair = (netsnmp_udp_addr_pair *) data;
00068 } else if (t != NULL && t->data != NULL) {
00069 addr_pair = (netsnmp_udp_addr_pair *) t->data;
00070 }
00071
00072 if (addr_pair == NULL) {
00073 return strdup("TCP: unknown");
00074 } else {
00075 struct sockaddr_in *to = NULL;
00076 char tmp[64];
00077 to = (struct sockaddr_in *) &(addr_pair->remote_addr);
00078 if (to == NULL) {
00079 return strdup("TCP: unknown");
00080 }
00081
00082 sprintf(tmp, "TCP: [%s]:%hd",
00083 inet_ntoa(to->sin_addr), ntohs(to->sin_port));
00084 return strdup(tmp);
00085 }
00086 }
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096 static int
00097 netsnmp_tcp_recv(netsnmp_transport *t, void *buf, int size,
00098 void **opaque, int *olength)
00099 {
00100 int rc = -1;
00101
00102 if (t != NULL && t->sock >= 0) {
00103 while (rc < 0) {
00104 rc = recv(t->sock, buf, size, 0);
00105 if (rc < 0 && errno != EINTR) {
00106 DEBUGMSGTL(("netsnmp_tcp", "recv fd %d err %d (\"%s\")\n",
00107 t->sock, errno, strerror(errno)));
00108 break;
00109 }
00110 DEBUGMSGTL(("netsnmp_tcp", "recv fd %d got %d bytes\n",
00111 t->sock, rc));
00112 }
00113 } else {
00114 return -1;
00115 }
00116
00117 if (opaque != NULL && olength != NULL) {
00118 if (t->data_length > 0) {
00119 if ((*opaque = malloc(t->data_length)) != NULL) {
00120 memcpy(*opaque, t->data, t->data_length);
00121 *olength = t->data_length;
00122 } else {
00123 *olength = 0;
00124 }
00125 } else {
00126 *opaque = NULL;
00127 *olength = 0;
00128 }
00129 }
00130
00131 return rc;
00132 }
00133
00134
00135
00136 static int
00137 netsnmp_tcp_send(netsnmp_transport *t, void *buf, int size,
00138 void **opaque, int *olength)
00139 {
00140 int rc = -1;
00141
00142 if (t != NULL && t->sock >= 0) {
00143 while (rc < 0) {
00144 rc = send(t->sock, buf, size, 0);
00145 if (rc < 0 && errno != EINTR) {
00146 break;
00147 }
00148 }
00149 }
00150 return rc;
00151 }
00152
00153
00154
00155 static int
00156 netsnmp_tcp_close(netsnmp_transport *t)
00157 {
00158 int rc = -1;
00159 if (t != NULL && t->sock >= 0) {
00160 DEBUGMSGTL(("netsnmp_tcp", "close fd %d\n", t->sock));
00161 #ifndef HAVE_CLOSESOCKET
00162 rc = close(t->sock);
00163 #else
00164 rc = closesocket(t->sock);
00165 #endif
00166 t->sock = -1;
00167 }
00168 return rc;
00169 }
00170
00171
00172
00173 static int
00174 netsnmp_tcp_accept(netsnmp_transport *t)
00175 {
00176 struct sockaddr *farend = NULL;
00177 netsnmp_udp_addr_pair *addr_pair = NULL;
00178 int newsock = -1, sockflags = 0;
00179 socklen_t farendlen = sizeof(struct sockaddr_in);
00180 char *str = NULL;
00181
00182 addr_pair = (netsnmp_udp_addr_pair *)malloc(sizeof(netsnmp_udp_addr_pair));
00183
00184 if (addr_pair == NULL) {
00185
00186
00187
00188 DEBUGMSGTL(("netsnmp_tcp", "accept: malloc failed\n"));
00189 return -1;
00190 }
00191 farend = (struct sockaddr_in *) &(addr_pair->remote_addr);
00192
00193 if (t != NULL && t->sock >= 0) {
00194 newsock = accept(t->sock, farend, &farendlen);
00195
00196 if (newsock < 0) {
00197 DEBUGMSGTL(("netsnmp_tcp", "accept failed rc %d errno %d \"%s\"\n",
00198 newsock, errno, strerror(errno)));
00199 free(farend);
00200 return newsock;
00201 }
00202
00203 if (t->data != NULL) {
00204 free(t->data);
00205 }
00206
00207 t->data = addr_pair;
00208 t->data_length = sizeof(netsnmp_udp_addr_pair);
00209 str = netsnmp_tcp_fmtaddr(NULL, farend, farendlen);
00210 DEBUGMSGTL(("netsnmp_tcp", "accept succeeded (from %s)\n", str));
00211 free(str);
00212
00213
00214
00215
00216
00217 #ifdef WIN32
00218 ioctlsocket(newsock, FIONBIO, &sockflags);
00219 #else
00220 if ((sockflags = fcntl(newsock, F_GETFL, 0)) >= 0) {
00221 fcntl(newsock, F_SETFL, (sockflags & ~O_NONBLOCK));
00222 } else {
00223 DEBUGMSGTL(("netsnmp_tcp", "couldn't f_getfl of fd %d\n",newsock));
00224 }
00225 #endif
00226
00227
00228
00229
00230
00231
00232 netsnmp_sock_buffer_set(newsock, SO_SNDBUF, 1, 0);
00233 netsnmp_sock_buffer_set(newsock, SO_RCVBUF, 1, 0);
00234
00235 return newsock;
00236 } else {
00237 free(farend);
00238 return -1;
00239 }
00240 }
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250 netsnmp_transport *
00251 netsnmp_tcp_transport(struct sockaddr_in *addr, int local)
00252 {
00253 netsnmp_transport *t = NULL;
00254 netsnmp_udp_addr_pair *addr_pair = NULL;
00255 int rc = 0;
00256
00257
00258 if (addr == NULL || addr->sin_family != AF_INET) {
00259 return NULL;
00260 }
00261
00262 t = (netsnmp_transport *) malloc(sizeof(netsnmp_transport));
00263 if (t == NULL) {
00264 return NULL;
00265 }
00266 memset(t, 0, sizeof(netsnmp_transport));
00267
00268 addr_pair = (netsnmp_udp_addr_pair *)malloc(sizeof(netsnmp_udp_addr_pair));
00269 if (addr_pair == NULL) {
00270 netsnmp_transport_free(t);
00271 return NULL;
00272 }
00273 t->data = addr_pair;
00274 t->data_length = sizeof(netsnmp_udp_addr_pair);
00275 memcpy(&(addr_pair->remote_addr), addr, sizeof(struct sockaddr_in));
00276
00277 t->domain = netsnmp_snmpTCPDomain;
00278 t->domain_length =
00279 sizeof(netsnmp_snmpTCPDomain) / sizeof(netsnmp_snmpTCPDomain[0]);
00280
00281 t->sock = socket(PF_INET, SOCK_STREAM, 0);
00282 if (t->sock < 0) {
00283 netsnmp_transport_free(t);
00284 return NULL;
00285 }
00286
00287 t->flags = NETSNMP_TRANSPORT_FLAG_STREAM;
00288
00289 if (local) {
00290 int sockflags = 0, opt = 1;
00291
00292
00293
00294
00295
00296
00297
00298 t->flags |= NETSNMP_TRANSPORT_FLAG_LISTEN;
00299 t->local = malloc(6);
00300 if (t->local == NULL) {
00301 netsnmp_tcp_close(t);
00302 netsnmp_transport_free(t);
00303 return NULL;
00304 }
00305 memcpy(t->local, (u_char *) & (addr->sin_addr.s_addr), 4);
00306 t->local[4] = (htons(addr->sin_port) & 0xff00) >> 8;
00307 t->local[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
00308 t->local_length = 6;
00309
00310
00311
00312
00313
00314 setsockopt(t->sock, SOL_SOCKET, SO_REUSEADDR, (void *)&opt,
00315 sizeof(opt));
00316
00317 rc = bind(t->sock, (struct sockaddr *)addr, sizeof(struct sockaddr));
00318 if (rc != 0) {
00319 netsnmp_tcp_close(t);
00320 netsnmp_transport_free(t);
00321 return NULL;
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332 #ifdef WIN32
00333 opt = 1;
00334 ioctlsocket(t->sock, FIONBIO, &opt);
00335 #else
00336 sockflags = fcntl(t->sock, F_GETFL, 0);
00337 fcntl(t->sock, F_SETFL, sockflags | O_NONBLOCK);
00338 #endif
00339
00340
00341
00342
00343
00344 rc = listen(t->sock, NETSNMP_STREAM_QUEUE_LEN);
00345 if (rc != 0) {
00346 netsnmp_tcp_close(t);
00347 netsnmp_transport_free(t);
00348 return NULL;
00349 }
00350
00351
00352
00353
00354
00355 } else {
00356 t->remote = malloc(6);
00357 if (t->remote == NULL) {
00358 netsnmp_tcp_close(t);
00359 netsnmp_transport_free(t);
00360 return NULL;
00361 }
00362 memcpy(t->remote, (u_char *) & (addr->sin_addr.s_addr), 4);
00363 t->remote[4] = (htons(addr->sin_port) & 0xff00) >> 8;
00364 t->remote[5] = (htons(addr->sin_port) & 0x00ff) >> 0;
00365 t->remote_length = 6;
00366
00367
00368
00369
00370
00371
00372
00373
00374 rc = connect(t->sock, (struct sockaddr *)addr,
00375 sizeof(struct sockaddr));
00376
00377 if (rc < 0) {
00378 netsnmp_tcp_close(t);
00379 netsnmp_transport_free(t);
00380 return NULL;
00381 }
00382
00383
00384
00385
00386
00387
00388 netsnmp_sock_buffer_set(t->sock, SO_SNDBUF, local, 0);
00389 netsnmp_sock_buffer_set(t->sock, SO_RCVBUF, local, 0);
00390 }
00391
00392
00393
00394
00395
00396
00397 t->msgMaxSize = 0x7fffffff;
00398 t->f_recv = netsnmp_tcp_recv;
00399 t->f_send = netsnmp_tcp_send;
00400 t->f_close = netsnmp_tcp_close;
00401 t->f_accept = netsnmp_tcp_accept;
00402 t->f_fmtaddr = netsnmp_tcp_fmtaddr;
00403
00404 return t;
00405 }
00406
00407
00408
00409 netsnmp_transport *
00410 netsnmp_tcp_create_tstring(const char *str, int local)
00411 {
00412 struct sockaddr_in addr;
00413
00414 if (netsnmp_sockaddr_in(&addr, str, 0)) {
00415 return netsnmp_tcp_transport(&addr, local);
00416 } else {
00417 return NULL;
00418 }
00419 }
00420
00421
00422
00423 netsnmp_transport *
00424 netsnmp_tcp_create_ostring(const u_char * o, size_t o_len, int local)
00425 {
00426 struct sockaddr_in addr;
00427
00428 if (o_len == 6) {
00429 unsigned short porttmp = (o[4] << 8) + o[5];
00430 addr.sin_family = AF_INET;
00431 memcpy((u_char *) & (addr.sin_addr.s_addr), o, 4);
00432 addr.sin_port = htons(porttmp);
00433 return netsnmp_tcp_transport(&addr, local);
00434 }
00435 return NULL;
00436 }
00437
00438
00439
00440 void
00441 netsnmp_tcp_ctor(void)
00442 {
00443 tcpDomain.name = netsnmp_snmpTCPDomain;
00444 tcpDomain.name_length = sizeof(netsnmp_snmpTCPDomain) / sizeof(oid);
00445 tcpDomain.prefix = calloc(2, sizeof(char *));
00446 tcpDomain.prefix[0] = "tcp";
00447
00448 tcpDomain.f_create_from_tstring = netsnmp_tcp_create_tstring;
00449 tcpDomain.f_create_from_ostring = netsnmp_tcp_create_ostring;
00450
00451 netsnmp_tdomain_register(&tcpDomain);
00452 }