/* * Copyright © 2005,2008 Red Hat, Inc. All rights reserved. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions of the * GNU General Public License v.2. This program is distributed in the hope * that it will be useful, but WITHOUT ANY WARRANTY expressed or implied, * including the implied warranties of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 51 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat * trademarks that are incorporated in the source code or documentation are not * subject to the GNU General Public License and may only be used or replicated * with the express permission of Red Hat, Inc. * * Red Hat Author(s): Nathan Straz * Dean Jansa */ #include #include #include #include #include #include #include #include #include #include #include #include #include "qarsh_packet.h" static int packet_seq = 1; /* Some generic socket related functions to make things easier */ int connect_to_host(char *hostname, int port, unsigned short *ss_family) { struct addrinfo *ail; struct addrinfo *aip; struct addrinfo hints; char portstr[NI_MAXSERV]; int sd; int err; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; memset(portstr, 0, sizeof portstr); snprintf(portstr, NI_MAXSERV, "%d", port); if ((err = getaddrinfo(hostname, portstr, &hints, &ail)) != 0) { fprintf(stderr, "Could not resolve hostname %s: %s\n", hostname, gai_strerror(err)); return -1; } /* TBD -- do we loop over all of the addrinfos returned trying to * connect, or just pick the first one? */ for (aip = ail; aip != NULL; aip = aip->ai_next) { #if 0 char hname[NI_MAXHOST] = ""; char nname[NI_MAXHOST] = ""; err = getnameinfo(aip->ai_addr, aip->ai_addrlen, hname, NI_MAXHOST, NULL, 0, 0); err = getnameinfo(aip->ai_addr, aip->ai_addrlen, nname, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (err != 0) { printf("error in getnameinfo: %s\n", gai_strerror(err)); continue; } if (*hname && *nname) { printf("Trying: %s (%s) -- ", hname, nname); if (aip->ai_family == AF_INET6) puts("IPv6"); if (aip->ai_family == AF_INET) puts("IPv4"); } #endif sd = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol); if (sd == -1) return -1; if (connect(sd, aip->ai_addr, aip->ai_addrlen) == -1) { close(sd); continue; } else { *ss_family=aip->ai_family; freeaddrinfo(ail); return sd; } } freeaddrinfo(ail); return -1; } /* * All incoming and outgoing packets go through this function. * Caller should make sure the fd is ready to read. */ struct qa_packet * recv_packet(int fd) { char buf[QARSH_MAX_PACKET_SIZE]; uint32_t packetsize; void *psbuf = &packetsize; int bufused = 0; int ret = 0; do { if ((ret = read(fd, (char *)psbuf+bufused, sizeof packetsize - bufused)) < 0) { fprintf(stderr, "Read error while reading packet size: %s\n", strerror(errno)); return NULL; } else if (ret == 0) { return NULL; } bufused += ret; } while (bufused < sizeof packetsize); packetsize = ntohl(packetsize); if (packetsize > QARSH_MAX_PACKET_SIZE) { fprintf(stderr, "Packet size too large, %d > %d\n", packetsize, QARSH_MAX_PACKET_SIZE); return NULL; } /* Keep reading until we get the whole packet and nothing but the packet, so help me socket */ bufused = 0; do { if ((ret = read(fd, buf+bufused, packetsize-bufused)) < 0) { fprintf(stderr, "Read error while reading packet data: %s\n", strerror(errno)); return NULL; } bufused += ret; } while (bufused < packetsize); return parse_packet(buf, packetsize); } int send_packet(int fd, struct qa_packet *qp) { char buf[QARSH_MAX_PACKET_SIZE]; uint32_t netsize; int len; ssize_t ret = -1; struct iovec iovs[2]; qp->qp_seq = packet_seq++; len = qptostr(qp, buf, QARSH_MAX_PACKET_SIZE - sizeof netsize); if (len > 0) { netsize = htonl(len); iovs[0].iov_base = &netsize; iovs[0].iov_len = sizeof netsize; iovs[1].iov_base = buf; iovs[1].iov_len = len; ret = writev(fd, iovs, 2); } return ret; }