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