📄 sockets.c
字号:
/* The timeout routine doesn't have to do anything, I just want the * recvfrom() call to abort with EINTR. */static int recv_timeout(){ return 0;}char * snmp_send_rec(struct sty *sty, SNMP_PKT_T *xmit_pkt, ipaddr_t *addr, void (*io_complete)(struct sty *, SNMP_PKT_T *rpkt), void (*io_error)(struct sty *, char *err_msg)){ SNMP_PKT_T *rcvd_pkt; EBUFFER_T ebuff; int rcode; static int sd; static int sd_valid = 0; struct sockaddr_in dest; struct sockaddr_in from; struct sockaddr *destptr; struct sockaddr *fromptr; static int *sdptr; int szfrom; int count; extern int errno; OCTET_T *cp; int i;#if INSTALL_on_winsock fd_set sockset; struct timeval timeout = {0, 0};#if INSTALL_SNMP_DEMO_AGENT_IPV6 ADDRINFO hints; ADDRINFO * pAddrInfo; char netStr [48]; const char * pUdpPort = "161";#endif#endif#if INSTALL_SNMP_DEMO_AGENT_IPV6#if INSTALL_on_winsock /* struct sockaddr_in6 destv6 winsock uses buffer returned by getaddrinfo */#define MY_WINSOCK_FROM_SIZE 28 char winSockFrom [MY_WINSOCK_FROM_SIZE];#else struct sockaddr_in6 destv6; struct sockaddr_in6 fromv6;#endif static int sd6; static int sd6_valid = 0;#endif EBufferInitialize(&ebuff); rcode = SNMP_Encode_Packet(xmit_pkt, &ebuff); if (packet_dump) { sty_printf(sty, "Sending %d bytes\n", EBufferUsed(&ebuff)); for (cp = ebuff.start_bp, i = 1; cp < ebuff.next_bp; cp++, i++) { sty_printf(sty, "%2x ", *cp & 0xff); if ((i % 16) == 0) sty_printf(sty, "\n"); } sty_printf(sty, "\n\n"); }#if INSTALL_SNMP_DEMO_AGENT_IPV6 if (addr->type == IPV4) { dest.sin_family = AF_INET; dest.sin_port = htons(udp_port); memcpy(&(dest.sin_addr), &(addr->addr), sizeof(struct in_addr)); destptr = (struct sockaddr *)&dest; fromptr = (struct sockaddr *)&from; sdptr = &sd; } else if (addr->type == IPV6) { destv6.sin6_family = AF_INET6; destv6.sin6_flowinfo = 0; destv6.sin6_port = htons(udp_port); destv6.sin6_scope_id = v6_scope; memcpy(&(destv6.sin6_addr), &(addr->addr), sizeof(struct in6_addr)); destptr = (struct sockaddr *)&destv6; fromptr = (struct sockaddr *)&fromv6; sdptr = &sd6; }#else dest.sin_family = AF_INET; dest.sin_port = htons(udp_port); memcpy(&(dest.sin_addr), &(addr->addr), sizeof(bits32_t)); destptr = (struct sockaddr *)&dest; fromptr = (struct sockaddr *)&from; sdptr = &sd;#endif #if INSTALL_SNMP_DEMO_AGENT_IPV6 /* If this is our first time through, then get a socket to use */ if (!sd6_valid && (sd6 = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) { SNMP_Free(xmit_pkt); EBufferClean(&ebuff); return "Can't get socket"; } else#endif /* If this is our first time through then get a socket to use */ if (!sd_valid && (sd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { SNMP_Free(xmit_pkt); EBufferClean(&ebuff); return "Can't get socket"; } else {#if INSTALL_on_winsock#else#ifdef SV_INTERRUPT struct sigvec vec, ovec; /* on sunos 4 the following line gets a warning of type mismatch, sun defines the handler as a void function, other operating systems such as mach define it as an int function. Ignore the warning */ vec.sv_handler = recv_timeout; vec.sv_mask = sigmask(SIGALRM); vec.sv_flags = SV_INTERRUPT; sigvec(SIGALRM, &vec, &ovec);#else signal(SIGALRM, recv_timeout);#endif /* SV_INTERRUPT */#endif /* INSTALL_on_winsock */ sd_valid = 1;#if INSTALL_SNMP_DEMO_AGENT_IPV6 sd6_valid = 1;#endif } for (count = 0; count <= retry_count; count++) { /* Send current contents of the ebuffer */#if INSTALL_SNMP_DEMO_AGENT_IPV6 if (destptr->sa_family == AF_INET) { if (sendto(sd, EBufferStart(&ebuff), EBufferUsed(&ebuff), 0, destptr, sizeof(struct sockaddr_in)) == -1) { SNMP_Free(xmit_pkt); EBufferClean(&ebuff); return "Sendto failed"; } } else if (sendto(sd6, EBufferStart(&ebuff), EBufferUsed(&ebuff), 0, destptr, sizeof(struct sockaddr_in6)) == -1) { SNMP_Free(xmit_pkt); EBufferClean(&ebuff); return "Sendto failed"; }#else if (sendto(sd, (void *)ebuff.start_bp, EBufferUsed(&ebuff), 0, (struct sockaddr *)destptr, sizeof(dest)) == -1) { SNMP_Free(xmit_pkt); EBufferClean(&ebuff); return "Sendto failed"; }#endif recv_again: /* set up to time out if it takes too long */#if INSTALL_on_winsock timeout.tv_sec = SOCKET_TIMEOUT; FD_ZERO(&sockset); FD_SET(*sdptr, &sockset); rcode = select(0, &sockset, NULL, NULL, &timeout); if (rcode == 0) { /* timeout */ SNMP_Free(xmit_pkt); EBufferClean(&ebuff); return "Receive timed out"; }#elif (!INSTALL_on_ntgcc) ualarm(snmp_timeout * 1000000L, snmp_timeout * 1000000L);#endif /* INSTALL_on_winsock */ /* Receive the response into rcvbuff */#if INSTALL_SNMP_DEMO_AGENT_IPV6 szfrom = (addr->type == IPV4) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);#else szfrom = sizeof(from);#endif rcode = recvfrom(*sdptr, rcvbuff, sizeof(rcvbuff), 0, (struct sockaddr *)fromptr, &szfrom);#if INSTALL_on_winsock#elif (!INSTALL_on_ntgcc) ualarm(0, 0); /* turn off timer */#endif /* INSTALL_on_winsock */#if INSTALL_on_winsock /* if it's a timeout, report to user */ if (rcode == -1) { SNMP_Free(xmit_pkt); EBufferClean(&ebuff); sty_printf(sty, "Error on receive: %d", WSAGetLastError()); return "Recvfrom failed"; }#else if (rcode == -1) { /* if it was the alarm then just go around again */ if (errno != EINTR) { SNMP_Free(xmit_pkt); EBufferClean(&ebuff); return "Recvfrom failed"; } }#endif /* INSTALL_on_winsock */ else { if (packet_dump) { sty_printf(sty, "Received %d bytes\n", rcode); for (cp = rcvbuff, i = 1; i <= rcode; cp++, i++) { sty_printf(sty, "%2x ", *cp & 0xff); if ((i % 16) == 0) sty_printf(sty, "\n"); } printf("\n\n"); } EBufferClean(&ebuff); if ((rcvd_pkt = SNMP_Decode_Packet(rcvbuff, rcode, (SNMPADDR_T *)fromptr, (SNMPADDR_T *)destptr)) == 0) { SNMP_Free(xmit_pkt); return "Error in SNMP decode of received packet\n"; } if (rcvd_pkt->pdu.std_pdu.request_id != xmit_pkt->pdu.std_pdu.request_id) goto recv_again; SNMP_Free(xmit_pkt); (*io_complete)(sty, rcvd_pkt); return 0; } sty_printf(sty, "\007"); /* beep for each retransmit */ } EBufferClean(&ebuff); return "retry timeout\n";}/* * No-ops to resolve various linkage problems. */UINT_32_T get_sysUpTime (OIDC_T lastmatch, int compc, OIDC_T *compl, char *cookie, SNMP_PKT_T *pkt){ return(0);}UINT_32_T sysuptime (){ return(0);}int glue_intlock(int x){ return x;}/* * Low level keyboard handler stuff. */static void (*kbd_handler)(unsigned char *, size_t);void keyboard_handler(void (*handler)(unsigned char *, size_t)){ kbd_handler = handler;}void keyboard_write(unsigned char *text, size_t length){ if (text && length) fwrite(text, length, sizeof(unsigned char), stdout);}/* * Run tasks. This is the main body of the task dispatcher. * This is NOT a normal tasks_run() function! * See snark/lib/snarkbsd.c for a normal example. */int tasks_run(){ char command_line[512]; struct task *task; cty->flags &= ~STY_FLAG_ECHOING; while (!snark_exit_flag) { if ((task = task_deq()) != 0) { if (task->func) task->func(task, task->cookie); continue; } if (fgets(command_line, sizeof(command_line), stdin) == NULL) snark_exit(0); else if (kbd_handler) kbd_handler(command_line, strlen(command_line)); else snark_exit(1); } snark_shutdown(); return snark_exit_value;}/* * Initialization and shutdown. * There's probably stuff I've forgotten, add as needed. */void snark_init(){#if INSTALL_on_winsock WSADATA wsadata; int serr = WSAStartup(DESIRED_WINSOCK_VERSION, &wsadata); if (serr != 0) { printf("Cannot initialize socket library, error %d", serr); exit(0); } if (wsadata.wVersion < MINIMUM_WINSOCK_VERSION) { printf("Unsupported Windows Sockets Version %02X.%02X.", LOBYTE(wsadata.wVersion), HIBYTE(wsadata.wVersion)); exit(0); }#endif /* INSTALL_on_winsock */ tasks_init(); envoy_init(); #if INSTALL_on_unix setlinebuf(stdout);#endif sty_init();}void snark_shutdown(){#if INSTALL_on_winsock WSACleanup();#endif}/* These are just dummy functions so that this code builds with a reasonable * set of options turned on. If you actually want to do anything involving * timers, these functions need to be fleshed out. Given that over BSD * sockets SNMPTALK is only a manager, this seems unlikely. */bits32_t envoy_now(void){return(0);}void envoy_call_timer (bits32_t when, void (*what)(void)){return;}#if (INSTALL_ENVOY_SNMP_PROXY)/****************************************************************************NAME: proxy_send_rtnPURPOSE: noop of a proxy rtn to keep everybody happyPARAMETERS: EBUFFER_T * The buffer to send ptr_t Information as to where to send the buffer.RETURNS: sbits32_t A reasonable timeout period for this transport ****************************************************************************/sbits32_t proxy_send_rtn(EBUFFER_T *ebuf, ptr_t cookie){return(0);}#endif /* #if (INSTALL_ENVOY_SNMP_PROXY) */#if 0/* dummy routines, in the future these may be required to keep linkers happy. currently they aren't needed so they are ifdeffed out. obviously if we start using them they will need to be filled in correctly. */void envoy_call_timer(bits32_t when, void (*what)(void)){return;}/* Glue routine to connect up to the attache now routine in snark/lib. We use this mechanism instead of envoy.h so we can compile most of the code without knowing what we are running on the top of */bits32_t envoy_now(void){return(0);}#endif#if (INSTALL_ENVOY_ENTITY_MIB)bits32_t envoy_get_sysuptime(){return 0;}#endif /* #if (INSTALL_ENVOY_ENTITY_MIB) */#if INSTALL_ENVOY_SNMP_VERSION_3#if INSTALL_ENVOY_SNMP_V3_TARGET/******************************************************************************** envoy_taddress_to_snmpaddr** This routine and its companion envoy_snmpaddr_to_taddress will be* used to convert between an SNMPADDR_T and a TAddress/TDomain pair.* In the case of these demos, the SNMPADDR_T is an opaque structure* equivalent to a (struct sockaddr_in). For SNMP over UDP, the* TDomain will always be 1.3.6.1.6.1.1, and the TAddress will be 6* bytes long: 4 bytes of address and 2 bytes of port, all in* network order.** RETURNS: 0 on success, -1 on failure.** SEE ALSO: envoy_snmpaddr_to_taddress()*/int envoy_taddress_to_snmpaddr(SNMPADDR_T *addr, OBJ_ID_T *tdomain, EBUFFER_T *taddress){struct sockaddr_in sock;bits16_t port;bits32_t ipaddr;OIDC_T udpdomain[] = {1, 3, 6, 1, 6, 1, 1}; if (oidcmp(tdomain->num_components, tdomain->component_list, sizeof(udpdomain)/sizeof(OIDC_T), udpdomain) == 1) { sock.sin_family = AF_INET; MEMCPY(&ipaddr, EBufferStart(taddress), 4); MEMCPY(&port, (EBufferStart(taddress) + 4), 2); sock.sin_port = port; sock.sin_addr.s_addr = ipaddr; MEMCPY(addr, &sock, sizeof(sock)); return 0; }return -1;}/******************************************************************************** envoy_snmpaddr_to_taddress** This routine and its companion envoy_taddress_to_snmpaddr will be* used to convert between an SNMPADDR_T and a TAddress/TDomain pair.* In the case of these demos, the SNMPADDR_T is an opaque structure* equivalent to a (struct sockaddr_in). For SNMP over UDP, the* TDomain will always be 1.3.6.1.6.1.1, and the TAddress will be 6* bytes long: 4 bytes of address and 2 bytes of port, all in* network order.** RETURNS: 0 on success, -1 on failure.** SEE ALSO: envoy_snmpaddr_to_taddress()*/int envoy_snmpaddr_to_taddress(SNMPADDR_T *addr, OBJ_ID_T *tdomain, EBUFFER_T *taddress){struct sockaddr *sock = (struct sockaddr *)addr;struct sockaddr_in sock_in;bits16_t port;bits32_t ipaddr;bits8_t tadd[6];OIDC_T udpdomain[] = {1, 3, 6, 1, 6, 1, 1};if (sock->sa_family == AF_INET) { (void) memcpy((char *)(&sock_in), (char *)addr, sizeof(struct sockaddr_in)); if (build_object_id(sizeof(udpdomain)/sizeof(OIDC_T), udpdomain, tdomain)) return -1; ipaddr = sock_in.sin_addr.s_addr; port = sock_in.sin_port; MEMCPY(tadd, &ipaddr, 4); MEMCPY(tadd + 4, &port, 2); if (EBufferAllocateLoad(BFL_IS_ALLOC, taddress, tadd, 6)) { Clean_Obj_ID(tdomain); return -1; } return 0; }return -1;}#endif /* #if INSTALL_ENVOY_SNMP_V3_TARGET */#endif /* #if INSTALL_ENVOY_SNMP_VERSION_3 */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -