void ping_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) { struct icmp_hdr *icmph = (struct icmp_hdr *)&ip->udp_src; struct in_addr src_ip; int eth_hdr_size; switch (icmph->type) { case ICMP_ECHO_REPLY: src_ip = net_read_ip((void *)&ip->ip_src); if (src_ip.s_addr == net_ping_ip.s_addr) net_set_state(NETLOOP_SUCCESS); return; case ICMP_ECHO_REQUEST: eth_hdr_size = net_update_ether(et, et->et_src, PROT_IP); debug_cond(DEBUG_DEV_PKT, "Got ICMP ECHO REQUEST, return %d bytes\n", eth_hdr_size + len); ip->ip_sum = 0; ip->ip_off = 0; net_copy_ip((void *)&ip->ip_dst, &ip->ip_src); net_copy_ip((void *)&ip->ip_src, &net_ip); ip->ip_sum = compute_ip_checksum(ip, IP_HDR_SIZE); icmph->type = ICMP_ECHO_REPLY; icmph->checksum = 0; icmph->checksum = compute_ip_checksum(icmph, len - IP_HDR_SIZE); net_send_packet((uchar *)et, eth_hdr_size + len); return; /* default: return;*/ } }
int rcon_command(int rsock, char *command) { int ret; rc_packet *packet = packet_build(RCON_PID, RCON_EXEC_COMMAND, command); if(packet == NULL) { connection_alive = 0; return 0; } ret = net_send_packet(rsock, packet); if(!ret) return 0; /* send failed */ packet = net_recv_packet(rsock); if(packet == NULL) return 0; if(packet->id != RCON_PID) return 0; /* wrong packet id */ if(!silent_mode) { /* if(packet->size == 10) { printf("Unknown command \"%s\". Type \"help\" or \"?\" for help.\n", command); } else */ if(packet->size > 10) packet_print(packet); } /* return 1 if world was saved */ return 1; }
void arp_raw_request(struct in_addr source_ip, const uchar *target_ethaddr, struct in_addr target_ip) { uchar *pkt; struct arp_hdr *arp; int eth_hdr_size; debug_cond(DEBUG_DEV_PKT, "ARP broadcast %d\n", arp_wait_try); pkt = arp_tx_packet; eth_hdr_size = net_set_ether(pkt, net_bcast_ethaddr, PROT_ARP); pkt += eth_hdr_size; arp = (struct arp_hdr *)pkt; arp->ar_hrd = htons(ARP_ETHER); arp->ar_pro = htons(PROT_IP); arp->ar_hln = ARP_HLEN; arp->ar_pln = ARP_PLEN; arp->ar_op = htons(ARPOP_REQUEST); memcpy(&arp->ar_sha, net_ethaddr, ARP_HLEN); /* source ET addr */ net_write_ip(&arp->ar_spa, source_ip); /* source IP addr */ memcpy(&arp->ar_tha, target_ethaddr, ARP_HLEN); /* target ET addr */ net_write_ip(&arp->ar_tpa, target_ip); /* target IP addr */ net_send_packet(arp_tx_packet, eth_hdr_size + ARP_HDR_SIZE); }
int net_send_udp_packet(uchar *ether, struct in_addr dest, int dport, int sport, int payload_len) { uchar *pkt; int eth_hdr_size; int pkt_hdr_size; /* make sure the net_tx_packet is initialized (net_init() was called) */ assert(net_tx_packet != NULL); if (net_tx_packet == NULL) return -1; /* convert to new style broadcast */ if (dest.s_addr == 0) dest.s_addr = 0xFFFFFFFF; /* if broadcast, make the ether address a broadcast and don't do ARP */ if (dest.s_addr == 0xFFFFFFFF) ether = (uchar *)net_bcast_ethaddr; pkt = (uchar *)net_tx_packet; eth_hdr_size = net_set_ether(pkt, ether, PROT_IP); pkt += eth_hdr_size; net_set_udp_header(pkt, dest, dport, sport, payload_len); pkt_hdr_size = eth_hdr_size + IP_UDP_HDR_SIZE; /* if MAC address was not discovered yet, do an ARP request */ if (memcmp(ether, net_null_ethaddr, 6) == 0) { debug_cond(DEBUG_DEV_PKT, "sending ARP for %pI4\n", &dest); /* save the ip and eth addr for the packet to send after arp */ net_arp_wait_packet_ip = dest; arp_wait_packet_ethaddr = ether; /* size of the waiting packet */ arp_wait_tx_packet_size = pkt_hdr_size + payload_len; /* and do the ARP request */ arp_wait_try = 1; arp_wait_timer_start = get_timer(0); arp_request(); return 1; /* waiting */ } else { debug_cond(DEBUG_DEV_PKT, "sending UDP to %pI4/%pM\n", &dest, ether); net_send_packet(net_tx_packet, pkt_hdr_size + payload_len); return 0; /* transmitted */ } }
int rcon_auth(int rsock, char *passwd) { int ret; rc_packet *packet = packet_build(RCON_PID, RCON_AUTHENTICATE, passwd); if(packet == NULL) return 0; ret = net_send_packet(rsock, packet); if(!ret) return 0; /* send failed */ packet = net_recv_packet(rsock); if(packet == NULL) return 0; /* return 1 if authentication OK */ return packet->id == -1 ? 0 : 1; }
static int sd_tcpoutput(int csocket, t_connection * c) { unsigned int currsize; unsigned int totsize; t_packet * packet; totsize = 0; for (;;) { currsize = conn_get_out_size(c); switch (net_send_packet(csocket,queue_peek_packet((t_queue const * const *)conn_get_out_queue(c)),&currsize)) /* avoid warning */ { case -1: conn_destroy(c); return -1; case 0: /* still working on it */ conn_set_out_size(c,currsize); return 0; /* bail out */ case 1: /* done sending */ packet = queue_pull_packet(conn_get_out_queue(c)); if (hexstrm) { fprintf(hexstrm,"%d: send class=%s[0x%02x] type=%s[0x%04x] length=%u\n", csocket, packet_get_class_str(packet),(unsigned int)packet_get_class(packet), packet_get_type_str(packet,packet_dir_from_server),packet_get_type(packet), packet_get_size(packet)); hexdump(hexstrm,packet_get_raw_data(packet,0),packet_get_size(packet)); } packet_del_ref(packet); conn_set_out_size(c,0); /* stop at about 2KB (or until out of packets or EWOULDBLOCK) */ if (totsize>2048 || queue_get_length((t_queue const * const *)conn_get_out_queue(c))<1) return 0; totsize += currsize; } } /* not reached */ }
static void socket_init(void) { //先连gated const char *gated_ip = config_get_string("GATED_IP"); int port = config_get_int("INTER_GATED_PORT"); int gated_fd = net_connect(gated_ip, port, 0); if (gated_fd < 0) { printf("fail to connect gated!!!\n"); exit(1); } g_gated_conn = net_new_connection(gated_fd, gated_read_cb, NULL, gated_error_cb); auth_packet_t authpack; authpack.cmd = AUTH_GAMED; authpack.len = sizeof(authpack); fprintf(stdout, "authpack.len = %d!!\n", authpack.len); int ret = net_send_packet(g_gated_conn, (void *)&authpack, sizeof(authpack)); fprintf(stdout, "ret = %d!!\n", ret); }
void readPacket () { action = READING; NRF_WriteRegister(NRF_STATUS, 0x70); NRF_ReceivePayload(NRF_R_RX_PAYLOAD, NET_PACKET_SIZE, unReadData); printf("in readPacket: type: %d id: %d seq: %d time_to_live: %d\n",unReadData[0],unReadData[1],unReadData[2], unReadData[3]); int aux = process_for_routing (unReadData); NRF_SendCommand(NRF_FLUSH_RX, 0xFF); action = WAITING; if (aux == 0) {// we have a packet to forward if (unReadData[3] < 3) { unReadData[3]++; net_send_packet(unReadData); } } else { if (unReadData[2] > last_seq) { dataToRead = 1; last_seq = unReadData[2]; } } }
void arp_receive(struct ethernet_hdr *et, struct ip_udp_hdr *ip, int len) { struct arp_hdr *arp; struct in_addr reply_ip_addr; uchar *pkt; int eth_hdr_size; /* * We have to deal with two types of ARP packets: * - REQUEST packets will be answered by sending our * IP address - if we know it. * - REPLY packates are expected only after we asked * for the TFTP server's or the gateway's ethernet * address; so if we receive such a packet, we set * the server ethernet address */ debug_cond(DEBUG_NET_PKT, "Got ARP\n"); arp = (struct arp_hdr *)ip; if (len < ARP_HDR_SIZE) { printf("bad length %d < %d\n", len, ARP_HDR_SIZE); return; } if (ntohs(arp->ar_hrd) != ARP_ETHER) return; if (ntohs(arp->ar_pro) != PROT_IP) return; if (arp->ar_hln != ARP_HLEN) return; if (arp->ar_pln != ARP_PLEN) return; if (net_ip.s_addr == 0) return; if (net_read_ip(&arp->ar_tpa).s_addr != net_ip.s_addr) return; switch (ntohs(arp->ar_op)) { case ARPOP_REQUEST: /* reply with our IP address */ debug_cond(DEBUG_DEV_PKT, "Got ARP REQUEST, return our IP\n"); pkt = (uchar *)et; eth_hdr_size = net_update_ether(et, et->et_src, PROT_ARP); pkt += eth_hdr_size; arp->ar_op = htons(ARPOP_REPLY); memcpy(&arp->ar_tha, &arp->ar_sha, ARP_HLEN); net_copy_ip(&arp->ar_tpa, &arp->ar_spa); memcpy(&arp->ar_sha, net_ethaddr, ARP_HLEN); net_copy_ip(&arp->ar_spa, &net_ip); #ifdef CONFIG_CMD_LINK_LOCAL /* * Work-around for brain-damaged Cisco equipment with * arp-proxy enabled. * * If the requesting IP is not on our subnet, wait 5ms to * reply to ARP request so that our reply will overwrite * the arp-proxy's instead of the other way around. */ if ((net_read_ip(&arp->ar_tpa).s_addr & net_netmask.s_addr) != (net_read_ip(&arp->ar_spa).s_addr & net_netmask.s_addr)) udelay(5000); #endif net_send_packet((uchar *)et, eth_hdr_size + ARP_HDR_SIZE); return; case ARPOP_REPLY: /* arp reply */ /* are we waiting for a reply */ if (!net_arp_wait_packet_ip.s_addr) break; #ifdef CONFIG_KEEP_SERVERADDR if (net_server_ip.s_addr == net_arp_wait_packet_ip.s_addr) { char buf[20]; sprintf(buf, "%pM", &arp->ar_sha); setenv("serveraddr", buf); } #endif reply_ip_addr = net_read_ip(&arp->ar_spa); /* matched waiting packet's address */ if (reply_ip_addr.s_addr == net_arp_wait_reply_ip.s_addr) { debug_cond(DEBUG_DEV_PKT, "Got ARP REPLY, set eth addr (%pM)\n", arp->ar_data); /* save address for later use */ if (arp_wait_packet_ethaddr != NULL) memcpy(arp_wait_packet_ethaddr, &arp->ar_sha, ARP_HLEN); net_get_arp_handler()((uchar *)arp, 0, reply_ip_addr, 0, len); /* set the mac address in the waiting packet's header and transmit it */ memcpy(((struct ethernet_hdr *)net_tx_packet)->et_dest, &arp->ar_sha, ARP_HLEN); net_send_packet(net_tx_packet, arp_wait_tx_packet_size); /* no arp request pending now */ net_arp_wait_packet_ip.s_addr = 0; arp_wait_tx_packet_size = 0; arp_wait_packet_ethaddr = NULL; } return; default: debug("Unexpected ARP opcode 0x%x\n", ntohs(arp->ar_op)); return; } }
static int proxy_process(unsigned short server_listen_port, struct sockaddr_in servaddr) { int lsock; struct sockaddr_in laddr; t_psock_fd_set rfds, wfds; int highest_fd; int udpsock; t_virtconn * vc; t_elem const * curr; int csocket; int ssocket; if ((udpsock = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_DGRAM,PSOCK_IPPROTO_UDP))<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not create UDP socket (psock_socket: %s)",pstrerror(psock_errno())); return -1; } if (psock_ctl(udpsock,PSOCK_NONBLOCK)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not set UDP listen socket to non-blocking mode (psock_ctl: %s)",pstrerror(psock_errno())); if ((lsock = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_STREAM,PSOCK_IPPROTO_TCP))<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not create listening socket (psock_socket: %s)",pstrerror(psock_errno())); psock_close(udpsock); return -1; } { int val=1; if (psock_setsockopt(lsock,PSOCK_SOL_SOCKET,PSOCK_SO_REUSEADDR,&val,(psock_t_socklen)sizeof(int))<0) eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set socket option SO_REUSEADDR (psock_setsockopt: %s)",lsock,pstrerror(psock_errno())); /* not a fatal error... */ } memset(&laddr,0,sizeof(laddr)); laddr.sin_family = PSOCK_AF_INET; laddr.sin_port = htons(server_listen_port); laddr.sin_addr.s_addr = htonl(INADDR_ANY); if (psock_bind(lsock,(struct sockaddr *)&laddr,(psock_t_socklen)sizeof(laddr))<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not bind socket to address 0.0.0.0:%hu TCP (psock_bind: %s)",server_listen_port,pstrerror(psock_errno())); psock_close(udpsock); psock_close(lsock); return -1; } memset(&laddr,0,sizeof(laddr)); laddr.sin_family = PSOCK_AF_INET; laddr.sin_port = htons(server_listen_port); laddr.sin_addr.s_addr = htonl(INADDR_ANY); if (psock_bind(udpsock,(struct sockaddr *)&laddr,(psock_t_socklen)sizeof(laddr))<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not bind socket to address 0.0.0.0:%hu UDP (psock_bind: %s)",server_listen_port,pstrerror(psock_errno())); psock_close(udpsock); psock_close(lsock); return -1; } eventlog(eventlog_level_info,__FUNCTION__,"bound to UDP port %hu",server_listen_port); /* tell socket to listen for connections */ if (psock_listen(lsock,LISTEN_QUEUE)<0) { eventlog(eventlog_level_error,__FUNCTION__,"could not listen (psock_listen: %s)",pstrerror(psock_errno())); psock_close(udpsock); psock_close(lsock); return -1; } if (psock_ctl(lsock,PSOCK_NONBLOCK)<0) eventlog(eventlog_level_error,__FUNCTION__,"could not set TCP listen socket to non-blocking mode (psock_ctl: %s)",pstrerror(psock_errno())); eventlog(eventlog_level_info,__FUNCTION__,"listening on TCP port %hu",server_listen_port); for (;;) { /* loop over all connections to create the sets for select() */ PSOCK_FD_ZERO(&rfds); PSOCK_FD_ZERO(&wfds); highest_fd = lsock; PSOCK_FD_SET(lsock,&rfds); if (udpsock>highest_fd) highest_fd = udpsock; PSOCK_FD_SET(udpsock,&rfds); LIST_TRAVERSE_CONST(virtconnlist(),curr) { vc = elem_get_data(curr); csocket = virtconn_get_client_socket(vc); if (queue_get_length((t_queue const * const *)virtconn_get_clientout_queue(vc))>0) PSOCK_FD_SET(csocket,&wfds); /* pending output, also check for writeability */ PSOCK_FD_SET(csocket,&rfds); if (csocket>highest_fd) highest_fd = csocket; switch (virtconn_get_state(vc)) { case virtconn_state_connecting: eventlog(eventlog_level_debug,__FUNCTION__,"waiting for %d to finish connecting",ssocket); ssocket = virtconn_get_server_socket(vc); PSOCK_FD_SET(ssocket,&wfds); /* wait for connect to complete */ if (ssocket>highest_fd) highest_fd = ssocket; break; case virtconn_state_connected: eventlog(eventlog_level_debug,__FUNCTION__,"checking for reading on connected socket %d",ssocket); ssocket = virtconn_get_server_socket(vc); if (queue_get_length((t_queue const * const *)virtconn_get_serverout_queue(vc))>0) PSOCK_FD_SET(ssocket,&wfds); /* pending output, also check for writeability */ PSOCK_FD_SET(ssocket,&rfds); if (ssocket>highest_fd) highest_fd = ssocket; break; default: /* avoid warning */ break; } } /* find which sockets need servicing */ if (psock_select(highest_fd+1,&rfds,&wfds,NULL,NULL)<0) { if (errno!=PSOCK_EINTR) eventlog(eventlog_level_error,__FUNCTION__,"select failed (select: %s)",pstrerror(errno)); continue; } /* check for incoming connection */ if (PSOCK_FD_ISSET(lsock,&rfds)) { int asock; struct sockaddr_in caddr; psock_t_socklen caddr_len; /* accept the connection */ caddr_len = sizeof(caddr); if ((asock = psock_accept(lsock,(struct sockaddr *)&caddr,&caddr_len))<0) { if (psock_errno()==PSOCK_EWOULDBLOCK || psock_errno()==PSOCK_ECONNABORTED) /* BSD, POSIX error for aborted connections, SYSV often uses EAGAIN */ eventlog(eventlog_level_error,__FUNCTION__,"client aborted connection (psock_accept: %s)",pstrerror(psock_errno())); else /* EAGAIN can mean out of resources _or_ connection aborted */ if (psock_errno()!=PSOCK_EINTR) eventlog(eventlog_level_error,__FUNCTION__,"could not accept new connection (psock_accept: %s)",pstrerror(psock_errno())); } else { int ssd; int val=1; eventlog(eventlog_level_info,__FUNCTION__,"[%d] accepted connection from %s:%hu",asock,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port)); if (psock_setsockopt(asock,PSOCK_SOL_SOCKET,PSOCK_SO_KEEPALIVE,&val,(psock_t_socklen)sizeof(val))<0) eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set socket option SO_KEEPALIVE (psock_setsockopt: %s)",asock,pstrerror(psock_errno())); /* not a fatal error */ if (psock_ctl(asock,PSOCK_NONBLOCK)<0) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set TCP socket to non-blocking mode (closing connection) (psock_ctl: %s)",asock,pstrerror(psock_errno())); psock_close(asock); } else if ((ssd = psock_socket(PSOCK_PF_INET,PSOCK_SOCK_STREAM,PSOCK_IPPROTO_TCP))<0) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could create TCP socket (closing connection) (psock_socket: %s)",asock,pstrerror(psock_errno())); psock_close(asock); } else if (psock_ctl(ssd,PSOCK_NONBLOCK)<0) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not set TCP socket to non-blocking mode (closing connection) (psock_ctl: %s)",asock,pstrerror(psock_errno())); psock_close(ssd); psock_close(asock); } else if (!(vc = virtconn_create(asock,ssd,ntohl(caddr.sin_addr.s_addr),BNETD_MIN_TEST_PORT))) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] unable to create new connection (closing connection)",asock); psock_close(ssd); psock_close(asock); } else { memset(&caddr,0,sizeof(caddr)); caddr.sin_family = PSOCK_AF_INET; caddr.sin_port = htons(virtconn_get_udpport(vc)); caddr.sin_addr.s_addr = htonl(virtconn_get_udpaddr(vc)); eventlog(eventlog_level_info,__FUNCTION__,"[%d] addr now %s:%hu",asock,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port)); } } } eventlog(eventlog_level_debug,__FUNCTION__,"checking for incoming UDP"); if (PSOCK_FD_ISSET(udpsock,&rfds)) { t_packet * upacket; struct sockaddr_in toaddr; struct sockaddr_in fromaddr; psock_t_socklen fromlen; int len; if (!(upacket = packet_create(packet_class_raw))) eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw packet for input"); else { /* packet_set_flags(upacket,PROXY_FLAG_UDP);*/ fromlen = sizeof(fromaddr); if ((len = psock_recvfrom(udpsock,packet_get_raw_data_build(upacket,0),MAX_PACKET_SIZE,0,(struct sockaddr *)&fromaddr,&fromlen))<0) { if (psock_errno()!=PSOCK_EINTR && psock_errno()!=PSOCK_EAGAIN && psock_errno()!=PSOCK_EWOULDBLOCK) eventlog(eventlog_level_error,__FUNCTION__,"could not recv UDP datagram (psock_recvfrom: %s)",pstrerror(psock_errno())); } else { if (fromaddr.sin_family!=PSOCK_AF_INET) eventlog(eventlog_level_error,__FUNCTION__,"got UDP datagram with bad address family %d",fromaddr.sin_family); else { char tempa[32]; char tempb[32]; packet_set_size(upacket,len); if (fromaddr.sin_addr.s_addr==servaddr.sin_addr.s_addr) /* from server */ { if ((curr = list_get_first_const(virtconnlist()))) /* hack.. find proper client */ { vc = elem_get_data(curr); memset(&toaddr,0,sizeof(toaddr)); toaddr.sin_family = PSOCK_AF_INET; toaddr.sin_port = htons(virtconn_get_udpport(vc)); toaddr.sin_addr.s_addr = htonl(virtconn_get_udpaddr(vc)); eventlog(eventlog_level_info,__FUNCTION__,"[%d] addr by UDP send is %s:%hu",virtconn_get_client_socket(vc),inet_ntoa(toaddr.sin_addr),ntohs(toaddr.sin_port)); if (hexstrm) { strcpy(tempa,inet_ntoa(fromaddr.sin_addr)); strcpy(tempb,inet_ntoa(toaddr.sin_addr)); fprintf(hexstrm,"%d: srv prot=UDP from=%s:%hu to=%s:%hu length=%d\n", udpsock, tempa, ntohs(fromaddr.sin_port), tempb, ntohs(toaddr.sin_port), len); hexdump(hexstrm,packet_get_raw_data(upacket,0),len); } /*queue_push_packet(virtconn_get_clientout_queue(__));*/ /* where to queue ... */ for (;;) /* hack.. just block for now */ { if (psock_sendto(udpsock,packet_get_raw_data_const(upacket,0),len,0, (struct sockaddr *)&toaddr,(psock_t_socklen)sizeof(toaddr))<len) { if (psock_errno()==PSOCK_EINTR || psock_errno()==PSOCK_EAGAIN || psock_errno()==PSOCK_EWOULDBLOCK) continue; eventlog(eventlog_level_error,__FUNCTION__,"could not send UDP datagram to client (psock_sendto: %s)",pstrerror(psock_errno())); } break; } } } else /* from client */ { if (hexstrm) { strcpy(tempa,inet_ntoa(fromaddr.sin_addr)); strcpy(tempb,inet_ntoa(servaddr.sin_addr)); fprintf(hexstrm,"%d: clt prot=UDP from=%s:%hu to=%s:%hu length=%d\n", udpsock, tempa, ntohs(fromaddr.sin_port), tempb, ntohs(servaddr.sin_port), len); hexdump(hexstrm,packet_get_raw_data(upacket,0),len); } /*queue_push_packet(virtconn_get_serverout_queue(vc));*/ for (;;) /* hack.. just block for now */ { if (psock_sendto(udpsock,packet_get_raw_data_const(upacket,0),len,0, (struct sockaddr *)&servaddr,(psock_t_socklen)sizeof(servaddr))<len) { if (psock_errno()==PSOCK_EINTR || psock_errno()==PSOCK_EAGAIN || psock_errno()==PSOCK_EWOULDBLOCK) continue; eventlog(eventlog_level_error,__FUNCTION__,"could not send UDP datagram to server (psock_sendto: %s)",pstrerror(psock_errno())); } break; } } } } packet_del_ref(upacket); } } /* search connections for sockets that need service */ eventlog(eventlog_level_debug,__FUNCTION__,"checking for sockets that need service"); LIST_TRAVERSE_CONST(virtconnlist(),curr) { unsigned int currsize; t_packet * packet; vc = elem_get_data(curr); csocket = virtconn_get_client_socket(vc); if (virtconn_get_state(vc)==virtconn_state_connected || virtconn_get_state(vc)==virtconn_state_connecting) ssocket = virtconn_get_server_socket(vc); else ssocket = -1; eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for client readability",csocket); if (PSOCK_FD_ISSET(csocket,&rfds)) { if (virtconn_get_state(vc)==virtconn_state_initial) { if (init_virtconn(vc,servaddr)<0) { virtconn_destroy(vc); continue; } } else { currsize = virtconn_get_clientin_size(vc); if (!queue_get_length(virtconn_get_clientin_queue(vc))) { switch (virtconn_get_class(vc)) { case virtconn_class_bnet: if (!(packet = packet_create(packet_class_bnet))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate normal packet for input"); continue; } break; case virtconn_class_file: if (!(packet = packet_create(packet_class_file))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate file packet for input"); continue; } break; case virtconn_class_bot: if (!(packet = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw packet for input"); continue; } packet_set_size(packet,1); /* start by only reading one char */ break; default: eventlog(eventlog_level_error,__FUNCTION__,"[%d] connection has bad type (closing connection)",virtconn_get_client_socket(vc)); virtconn_destroy(vc); continue; } queue_push_packet(virtconn_get_clientin_queue(vc),packet); packet_del_ref(packet); if (!queue_get_length(virtconn_get_clientin_queue(vc))) continue; /* push failed */ currsize = 0; } packet = queue_peek_packet((t_queue const * const *)virtconn_get_clientin_queue(vc)); /* avoid warning */ switch (net_recv_packet(csocket,packet,&currsize)) { case -1: virtconn_destroy(vc); continue; case 0: /* still working on it */ virtconn_set_clientin_size(vc,currsize); break; case 1: /* done reading */ if (virtconn_get_class(vc)==virtconn_class_bot && currsize<MAX_PACKET_SIZE) { char const * const temp=packet_get_raw_data_const(packet,0); if (temp[currsize-1]!='\r' && temp[currsize-1]!='\n') { virtconn_set_clientin_size(vc,currsize); packet_set_size(packet,currsize+1); break; /* no end of line, get another char */ } /* got a complete line... fall through */ } packet = queue_pull_packet(virtconn_get_clientin_queue(vc)); if (hexstrm) { fprintf(hexstrm,"%d: cli class=%s[0x%04hx] type=%s[0x%04hx] length=%hu\n", csocket, packet_get_class_str(packet),packet_get_class(packet), packet_get_type_str(packet,packet_dir_from_client),packet_get_type(packet), packet_get_size(packet)); hexdump(hexstrm,packet_get_raw_data_const(packet,0),packet_get_size(packet)); } queue_push_packet(virtconn_get_serverout_queue(vc),packet); packet_del_ref(packet); virtconn_set_clientin_size(vc,0); } } } eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for server readability",ssocket); if (ssocket!=-1 && PSOCK_FD_ISSET(ssocket,&rfds)) { currsize = virtconn_get_serverin_size(vc); if (!queue_get_length(virtconn_get_serverin_queue(vc))) { switch (virtconn_get_class(vc)) { case virtconn_class_bnet: if (!(packet = packet_create(packet_class_bnet))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate normal packet for input"); continue; } break; case virtconn_class_file: { unsigned int fileleft; if ((fileleft = virtconn_get_fileleft(vc))>0) { if (!(packet = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw file packet for input"); continue; } if (fileleft>MAX_PACKET_SIZE) packet_set_size(packet,MAX_PACKET_SIZE); else packet_set_size(packet,fileleft); } else { if (!(packet = packet_create(packet_class_file))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate file packet for input"); continue; } } } break; case virtconn_class_bot: if (!(packet = packet_create(packet_class_raw))) { eventlog(eventlog_level_error,__FUNCTION__,"could not allocate raw packet for input"); continue; } packet_set_size(packet,MAX_PACKET_SIZE); /* read as much as possible */ break; default: eventlog(eventlog_level_error,__FUNCTION__,"[%d] connection has bad type (closing connection)",virtconn_get_client_socket(vc)); virtconn_destroy(vc); continue; } queue_push_packet(virtconn_get_serverin_queue(vc),packet); packet_del_ref(packet); if (!queue_get_length(virtconn_get_serverin_queue(vc))) continue; /* push failed */ currsize = 0; } packet = queue_peek_packet((t_queue const * const *)virtconn_get_serverin_queue(vc)); /* avoid warning */ switch (net_recv_packet(ssocket,packet,&currsize)) { case -1: virtconn_destroy(vc); continue; case 0: /* still working on it */ virtconn_set_serverin_size(vc,currsize); if (virtconn_get_class(vc)!=virtconn_class_bot || currsize<1) break; else packet_set_size(packet,currsize); /* fallthough... we take what we can get with the bot data */ case 1: /* done reading */ packet = queue_pull_packet(virtconn_get_serverin_queue(vc)); if (virtconn_get_class(vc)==virtconn_class_file) { unsigned int len=virtconn_get_fileleft(vc); if (len) virtconn_set_fileleft(vc,len-currsize); else if (packet_get_type(packet)==SERVER_FILE_REPLY && packet_get_size(packet)>=sizeof(t_server_file_reply)) virtconn_set_fileleft(vc,bn_int_get(packet->u.server_file_reply.filelen)); } queue_push_packet(virtconn_get_clientout_queue(vc),packet); packet_del_ref(packet); virtconn_set_serverin_size(vc,0); } } eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for client writeability",csocket); if (PSOCK_FD_ISSET(csocket,&wfds)) { currsize = virtconn_get_clientout_size(vc); switch (net_send_packet(csocket,queue_peek_packet((t_queue const * const *)virtconn_get_clientout_queue(vc)),&currsize)) /* avoid warning */ { case -1: virtconn_destroy(vc); continue; case 0: /* still working on it */ virtconn_set_clientout_size(vc,currsize); break; case 1: /* done sending */ packet = queue_pull_packet(virtconn_get_clientout_queue(vc)); if (hexstrm) { fprintf(hexstrm,"%d: srv class=%s[0x%04hx] type=%s[0x%04hx] length=%hu\n", csocket, packet_get_class_str(packet),packet_get_class(packet), packet_get_type_str(packet,packet_dir_from_server),packet_get_type(packet), packet_get_size(packet)); hexdump(hexstrm,packet_get_raw_data(packet,0),packet_get_size(packet)); } packet_del_ref(packet); virtconn_set_clientout_size(vc,0); } } eventlog(eventlog_level_debug,__FUNCTION__,"checking %d for server writeability",ssocket); if (ssocket!=-1 && PSOCK_FD_ISSET(ssocket,&wfds)) { if (virtconn_get_state(vc)==virtconn_state_connecting) { int err; psock_t_socklen errlen; err = 0; errlen = sizeof(err); if (psock_getsockopt(ssocket,PSOCK_SOL_SOCKET,PSOCK_SO_ERROR,&err,&errlen)<0) { eventlog(eventlog_level_error,__FUNCTION__,"[%d] unable to read socket error (psock_getsockopt[psock_connect]: %s)",virtconn_get_client_socket(vc),pstrerror(psock_errno())); virtconn_destroy(vc); continue; } if (errlen==0 || err==0) virtconn_set_state(vc,virtconn_state_connected); else { eventlog(eventlog_level_error,__FUNCTION__,"[%d] could not connect to server (psock_getsockopt[psock_connect]: %s)",virtconn_get_client_socket(vc),pstrerror(err)); virtconn_destroy(vc); continue; } } else { currsize = virtconn_get_serverout_size(vc); switch (net_send_packet(ssocket,queue_peek_packet((t_queue const * const *)virtconn_get_serverout_queue(vc)),&currsize)) /* avoid warning */ { case -1: virtconn_destroy(vc); continue; case 0: /* still working on it */ virtconn_set_serverout_size(vc,currsize); break; case 1: /* done sending */ packet = queue_pull_packet(virtconn_get_serverout_queue(vc)); packet_del_ref(packet); virtconn_set_serverout_size(vc,0); } } } }