• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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