SoDaRadio-5.0.3-master:8901fb5
IPSockets.cxx
Go to the documentation of this file.
1 /*
2  Copyright (c) 2012, Matthew H. Reilly (kb1vc)
3  All rights reserved.
4 
5  Redistribution and use in source and binary forms, with or without
6  modification, are permitted provided that the following conditions are
7  met:
8 
9  Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in
13  the documentation and/or other materials provided with the
14  distribution.
15 
16  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20  HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include "IPSockets.hxx"
30 #include <stdexcept>
31 #include <iostream>
32 #include <unistd.h>
33 #include <netdb.h>
34 #include <sys/select.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <sys/time.h>
38 #include <unistd.h>
39 #include <sys/ioctl.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 
44 {
45  int stat;
46  // create the socket.
47  if(transport == TCP) {
48  server_socket = socket(AF_INET, SOCK_STREAM, 0);
49  }
50  else if (transport == UDP) {
51  server_socket = socket(AF_INET, SOCK_DGRAM, 0);
52  }
53 
54  if(server_socket < 0) {
55  std::cerr << "Failed to create server socket... I quit." << std::endl;
56  exit(-1);
57  }
58 
59  int x = fcntl(server_socket, F_GETFL, 0);
60  fcntl(server_socket, F_SETFL, x | O_NONBLOCK);
61 
62  // setup the server address
63  bzero((char*) &server_address, sizeof(server_address));
64  server_address.sin_family = AF_INET;
65  server_address.sin_addr.s_addr = INADDR_ANY;
66  server_address.sin_port = htons(portnum);
67 
68  // now bind it
69  if (bind(server_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
70  std::cerr << "Couldn't bind socket at port number " << portnum << " I quit." << std::endl;
71  exit(-1);
72  }
73 
74  // now let the world know that we're ready for one and only one connection.
75  stat = listen(server_socket, 5);
76  if(stat < 0) {
77  std::cerr << "Couldn't listen on port number " << portnum << " got " << errno << " I quit." << std::endl;
78  exit(-1);
79  }
80 
81  // mark the socket as "not ready" for input -- it needs to accept first.
82  ready = false;
83 }
84 
85 SoDa::IP::ClientSocket::ClientSocket(const char * hostname, int portnum, TransportType transport)
86 {
87  if(transport == TCP) {
88  conn_socket = socket(AF_INET, SOCK_STREAM, 0);
89  }
90  else if(transport == UDP) {
91  conn_socket = socket(AF_INET, SOCK_DGRAM, 0);
92  }
93 
94  if(conn_socket < 0) {
95  std::cerr << "Failed to create client socket... I quit." << std::endl;
96  exit(-1);
97  }
98 
99  server = gethostbyname(hostname);
100  if(server == NULL) {
101  std::cerr << "Couldn't find server named [" << hostname << "]... I quit." << std::endl;
102  exit(-1);
103  }
104 
105  bzero((char*) &server_address, sizeof(server_address));
106  server_address.sin_family = AF_INET;
107  bcopy((char *) server->h_addr, (char*) &server_address.sin_addr.s_addr, server->h_length);
108  server_address.sin_port = htons(portnum);
109 
110  if(connect(conn_socket, (struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
111  std::cerr << "Couldn't connect to host [" << hostname << "] at port number " << portnum << " I quit." << std::endl;
112  perror("oops.");
113  exit(-1);
114  }
115 
116  setNonBlocking();
117 }
118 
120 {
121  if(ready) return true;
122  else {
123  socklen_t ca_len = sizeof(client_address);
124  // note that we've set the server_socket to non-block, so if nobody is here,
125  // we should get an EAGAIN or EWOULDBLOCK.
126  int ns = accept(server_socket, (struct sockaddr *) & client_address, &ca_len);
127  if(ns < 0) {
128  ready = false;
129  }
130  else {
131  conn_socket = ns;
132  int x = fcntl(conn_socket, F_GETFL, 0);
133  fcntl(conn_socket, F_SETFL, x | O_NONBLOCK);
134  ready = true;
135  }
136  }
137  return ready;
138 }
139 
140 int SoDa::IP::NetSocket::loopWrite(int fd, const void * ptr, unsigned int nbytes)
141 {
142  char * bptr = (char*) ptr;
143  int left = nbytes;
144  int stat;
145  while(left > 0) {
146  stat = write(fd, bptr, left);
147  if(stat < 0) {
148  if((errno == EWOULDBLOCK) || (errno == EAGAIN)) {
149  continue;
150  }
151  else {
152  return stat;
153  }
154  }
155  else {
156  left -= stat;
157  bptr += stat;
158  }
159  }
160 
161  return 0;
162 }
163 
164 int SoDa::IP::NetSocket::put(const void * ptr, unsigned int size)
165 {
166  // we always put a buffer of bytes, preceded by a count of bytes to be sent.
167  int stat;
168 
169  stat = loopWrite(conn_socket, &size, sizeof(unsigned int));
170  if(stat < 0) return stat;
171 
172  stat = loopWrite(conn_socket, ptr, size);
173 
174  return stat;
175 }
176 
177 int SoDa::IP::NetSocket::get(void * ptr, unsigned int size)
178 {
179  int stat;
180  unsigned int rsize;
181 
182  stat = read(conn_socket, &rsize, sizeof(unsigned int));
183  if(stat <= 0) {
184  if((errno == EWOULDBLOCK) || (errno == EAGAIN)) {
185  // std::cerr << ">>>" << std::endl;
186  return 0;
187  }
188  else {
189  perror("Oops -- socket get -- ");
190  return stat;
191  }
192  }
193 
194  int left = rsize;
195  char * bptr = (char*) ptr;
196  while(left > 0) {
197  int ls = read(conn_socket, bptr, left);
198  if(ls < 0) {
199  if((errno == EWOULDBLOCK) || (errno == EAGAIN)) {
200  continue;
201  }
202  else {
203  perror("Ooops -- read buffer continued");
204  return ls;
205  }
206  }
207  else {
208  left -= ls;
209  bptr += ls;
210  }
211  }
212 
213  if(rsize > size) {
214  char dmy[100];
215  unsigned int left = rsize - size;
216  while(left != 0) {
217  int ls;
218  ls = read(conn_socket, dmy, (left > 100) ? 100 : left);
219  if(ls < 0) {
220  if((errno == EWOULDBLOCK) || (errno == EAGAIN)) {
221  continue;
222  }
223  else {
224  perror("Ooops -- read buffer continued");
225  return ls;
226  }
227  }
228  left -= ls;
229  }
230  }
231 
232  return size;
233 
234 }
235 
236 
237 
238 
239 int SoDa::IP::NetSocket::putRaw(const void * ptr, unsigned int size)
240 {
241  int stat = loopWrite(conn_socket, ptr, size);
242  return stat;
243 }
244 
245 int SoDa::IP::NetSocket::getRaw(const void * ptr, unsigned int size, unsigned int usec_timeout)
246 {
247 
248  if(usec_timeout != 0) {
250  struct timeval tv;
251  tv.tv_sec = 0;
252  tv.tv_usec = usec_timeout;
253  int stat = setsockopt(conn_socket, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
254  if (stat < 0) {
255  throw std::runtime_error("Failed to put client socket in timeout mode\n");
256  }
257  }
258  else {
260  }
261 
262  unsigned int left = size;
263  char * bptr = (char*) ptr;
264  int timeout_count = 0;
265  while(left > 0) {
266  int ls;
267  // ls = read(conn_socket, bptr, left);
268  ls = recv(conn_socket, bptr, left, 0);
269  if(ls < 0) {
270  if((errno == EWOULDBLOCK) || (errno == EAGAIN)) {
271  timeout_count++;
272  if(timeout_count > 2) {
273  if(left == size) {
274  throw ReadTimeoutExc("Client");
275  }
276  else return size - (left + ls);
277  }
278  continue;
279  }
280  else {
281  perror("Ooops -- read buffer continued");
282  return ls;
283  }
284  }
285  else {
286  left -= ls;
287  bptr += ls;
288  }
289  }
290 
291  return size;
292 
293 }
int putRaw(const void *ptr, unsigned int size)
Definition: IPSockets.cxx:239
int loopWrite(int fd, const void *ptr, unsigned int nbytes)
Definition: IPSockets.cxx:140
ClientSocket(const char *hostname, int portnum, TransportType transport=TCP)
Definition: IPSockets.cxx:85
int getRaw(const void *ptr, unsigned int size, unsigned int usec_timeout=0)
get a raw string of <size> bytes...
Definition: IPSockets.cxx:245
ServerSocket(int portnum, TransportType transport=TCP)
Definition: IPSockets.cxx:43
int put(const void *ptr, unsigned int size)
Definition: IPSockets.cxx:164
int get(void *ptr, unsigned int size)
Definition: IPSockets.cxx:177
struct sockaddr_in server_address client_address
Definition: IPSockets.hxx:94