1 /******************************************************************************* 2 * Copyright (c) 2014, 2017 IBM Corp. 3 * 4 * All rights reserved. This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License v1.0 6 * and Eclipse Distribution License v1.0 which accompany this distribution. 7 * 8 * The Eclipse Public License is available at 9 * http://www.eclipse.org/legal/epl-v10.html 10 * and the Eclipse Distribution License is available at 11 * http://www.eclipse.org/org/documents/edl-v10.php. 12 * 13 * Contributors: 14 * Ian Craggs - initial API and implementation and/or initial documentation 15 * Ian Craggs - ensure read returns if no bytes read 16 *******************************************************************************/ 17 18 #include <sys/types.h> 19 #include <sys/socket.h> 20 #include <sys/param.h> 21 #include <sys/time.h> 22 #include <sys/select.h> 23 #include <netinet/in.h> 24 #include <netinet/tcp.h> 25 #include <arpa/inet.h> 26 #include <netdb.h> 27 #include <stdio.h> 28 #include <unistd.h> 29 #include <errno.h> 30 #include <fcntl.h> 31 32 #include <stdlib.h> 33 #include <string.h> 34 #include <signal.h> 35 36 37 class IPStack 38 { 39 public: IPStack()40 IPStack() 41 { 42 43 } 44 connect(const char * hostname,int port)45 int connect(const char* hostname, int port) 46 { 47 int type = SOCK_STREAM; 48 struct sockaddr_in address; 49 int rc = -1; 50 sa_family_t family = AF_INET; 51 struct addrinfo *result = NULL; 52 struct addrinfo hints = {0, AF_UNSPEC, SOCK_STREAM, IPPROTO_TCP, 0, NULL, NULL, NULL}; 53 54 if ((rc = getaddrinfo(hostname, NULL, &hints, &result)) == 0) 55 { 56 struct addrinfo* res = result; 57 58 /* prefer ip4 addresses */ 59 while (res) 60 { 61 if (res->ai_family == AF_INET) 62 { 63 result = res; 64 break; 65 } 66 res = res->ai_next; 67 } 68 69 if (result->ai_family == AF_INET) 70 { 71 address.sin_port = htons(port); 72 address.sin_family = family = AF_INET; 73 address.sin_addr = ((struct sockaddr_in*)(result->ai_addr))->sin_addr; 74 } 75 else 76 rc = -1; 77 78 freeaddrinfo(result); 79 } 80 81 if (rc == 0) 82 { 83 mysock = socket(family, type, 0); 84 if (mysock != -1) 85 { 86 int opt = 1; 87 88 //if (setsockopt(mysock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&opt, sizeof(opt)) != 0) 89 // printf("Could not set SO_NOSIGPIPE for socket %d", mysock); 90 91 rc = ::connect(mysock, (struct sockaddr*)&address, sizeof(address)); 92 } 93 } 94 95 return rc; 96 } 97 98 // return -1 on error, or the number of bytes read 99 // which could be 0 on a read timeout read(unsigned char * buffer,int len,int timeout_ms)100 int read(unsigned char* buffer, int len, int timeout_ms) 101 { 102 struct timeval interval = {timeout_ms / 1000, (timeout_ms % 1000) * 1000}; 103 if (interval.tv_sec < 0 || (interval.tv_sec == 0 && interval.tv_usec <= 0)) 104 { 105 interval.tv_sec = 0; 106 interval.tv_usec = 100; 107 } 108 109 setsockopt(mysock, SOL_SOCKET, SO_RCVTIMEO, (char *)&interval, sizeof(struct timeval)); 110 111 int bytes = 0; 112 int i = 0; const int max_tries = 10; 113 while (bytes < len) 114 { 115 int rc = ::recv(mysock, &buffer[bytes], (size_t)(len - bytes), 0); 116 if (rc == -1) 117 { 118 if (errno != EAGAIN && errno != EWOULDBLOCK) 119 bytes = -1; 120 break; 121 } 122 else 123 bytes += rc; 124 if (++i >= max_tries) 125 break; 126 if (rc == 0) 127 break; 128 } 129 return bytes; 130 } 131 write(unsigned char * buffer,int len,int timeout)132 int write(unsigned char* buffer, int len, int timeout) 133 { 134 struct timeval tv; 135 136 tv.tv_sec = 0; /* 30 Secs Timeout */ 137 tv.tv_usec = timeout * 1000; // Not init'ing this can cause strange errors 138 139 setsockopt(mysock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv,sizeof(struct timeval)); 140 int rc = ::write(mysock, buffer, len); 141 //printf("write rc %d\n", rc); 142 return rc; 143 } 144 disconnect()145 int disconnect() 146 { 147 return ::close(mysock); 148 } 149 150 private: 151 152 int mysock; 153 }; 154 155 156 class Countdown 157 { 158 public: Countdown()159 Countdown() 160 { 161 162 } 163 Countdown(int ms)164 Countdown(int ms) 165 { 166 countdown_ms(ms); 167 } 168 169 expired()170 bool expired() 171 { 172 struct timeval now, res; 173 gettimeofday(&now, NULL); 174 timersub(&end_time, &now, &res); 175 //printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000); 176 //if (res.tv_sec > 0 || res.tv_usec > 0) 177 // printf("expired %d %d\n", res.tv_sec, res.tv_usec); 178 return res.tv_sec < 0 || (res.tv_sec == 0 && res.tv_usec <= 0); 179 } 180 181 countdown_ms(int ms)182 void countdown_ms(int ms) 183 { 184 struct timeval now; 185 gettimeofday(&now, NULL); 186 struct timeval interval = {ms / 1000, (ms % 1000) * 1000}; 187 //printf("interval %d %d\n", interval.tv_sec, interval.tv_usec); 188 timeradd(&now, &interval, &end_time); 189 } 190 191 countdown(int seconds)192 void countdown(int seconds) 193 { 194 struct timeval now; 195 gettimeofday(&now, NULL); 196 struct timeval interval = {seconds, 0}; 197 timeradd(&now, &interval, &end_time); 198 } 199 200 left_ms()201 int left_ms() 202 { 203 struct timeval now, res; 204 gettimeofday(&now, NULL); 205 timersub(&end_time, &now, &res); 206 //printf("left %d ms\n", (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000); 207 return (res.tv_sec < 0) ? 0 : res.tv_sec * 1000 + res.tv_usec / 1000; 208 } 209 210 private: 211 212 struct timeval end_time; 213 }; 214