3
// safe, easy connection-related functions for VoxBo and beyond!
4
// Copyright (c) 1998-2008 by The VoxBo Development Team
6
// This file is part of VoxBo
8
// VoxBo is free software: you can redistribute it and/or modify it
9
// under the terms of the GNU General Public License as published by
10
// the Free Software Foundation, either version 3 of the License, or
11
// (at your option) any later version.
13
// VoxBo is distributed in the hope that it will be useful, but
14
// WITHOUT ANY WARRANTY; without even the implied warranty of
15
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16
// General Public License for more details.
18
// You should have received a copy of the GNU General Public License
19
// along with VoxBo. If not, see <http://www.gnu.org/licenses/>.
21
// For general information on VoxBo, including the latest complete
22
// source code and binary distributions, manual, and associated files,
23
// see the VoxBo home page at: http://www.voxbo.org/
25
// original version written by Dan Kimberg
32
#include <sys/types.h>
34
#include <sys/socket.h>
35
#include <netinet/in.h>
41
// buffer size for send/receive file
42
#define F_BUFSIZE 65536
45
safe_recv(int sock,char *buf,int len,float secs)
48
struct timeval t_start,t_deadline,t_current,t_timeout;
51
// buf is valid even if we fail utterly
53
// before we do anything time-consuming, set a deadline
54
gettimeofday(&t_start,NULL);
55
t_deadline.tv_sec = (int)secs;
56
t_deadline.tv_usec = lround(((secs - floor(secs))*1000000.0));
57
t_deadline=t_start+t_deadline;
60
// create socket mask for just the one socket
63
// timeout as specified
64
gettimeofday(&t_current,NULL);
65
t_timeout=t_deadline-t_current;
66
// make sure there's data available
67
err = select(sock+1,&ff,NULL,NULL,&t_timeout);
70
err=recv(sock,buf+pos,len-pos,0);
71
// break if we didn't get anything before the deadline
72
// buf[pos+err]='\0'; // FIXME
75
if (errno==EAGAIN) // FIXME not needed now that we're nonblocking
81
// break if we got something EOT-terminated
84
// break if we filled the buffer
88
// null-terminate if there's room, in case someone lazy uses it as a string
89
if (pos > 0 && pos<len)
95
safe_send(int sock,char *buf,int len,float secs)
97
// safe_send() just makes sure the socket is writeable before we send.
98
// at present it does not try to break the message up into pieces if
99
// it's too big. so whoever calls safe_send should be careful of
103
struct timeval t_start,t_deadline,t_current,t_timeout;
106
// before we do anything time-consuming, set a deadline
107
gettimeofday(&t_start,NULL);
108
t_deadline.tv_sec = (int)secs;
109
t_deadline.tv_usec = lround(((secs - floor(secs))*1000000.0));
110
t_deadline=t_start+t_deadline;
112
// create socket mask for just the one socket
115
// timeout as specified
116
gettimeofday(&t_current,NULL);
117
t_timeout=t_deadline-t_current;
118
// make sure we can send
119
err = select(sock+1,NULL,&ff,NULL,&t_timeout);
122
err=send(sock,buf,len,0);
130
safe_connect(struct sockaddr_in *addr,float secs)
132
return safe_connect((struct sockaddr *)addr,secs);
136
safe_connect(struct sockaddr_un *addr,float secs)
138
return safe_connect((struct sockaddr *)addr,secs);
142
safe_connect(struct sockaddr *addr,float secs)
144
// safe_connect() is a version of connect that will timeout after a
145
// given deadline. to do this correctly, we put the socket in
146
// nonblocking mode first, call connect, and if connect doesn't fail
147
// immediately, we're either connected or in EINPROGRESS. if the
148
// latter, we can use getsockopt to see if there's an error. see
149
// http://www.lcg.org/sock-faq/connect.c for some details.
150
// (non-blocking send/recv is a lot easier. just use select() with a
151
// timeout to make sure the socket is ready to read/write.)
157
s = socket(addr->sa_family,SOCK_STREAM,0);
161
fcntl(s,F_SETFL,O_NONBLOCK);
163
if (addr->sa_family==AF_INET)
164
sz=sizeof(struct sockaddr_in);
166
sz=sizeof(struct sockaddr_un);
167
err = connect(s,addr,sz);
168
if (err && (errno != EINPROGRESS)) {
172
// set up for select()
175
tv.tv_sec = (int)secs;
176
tv.tv_usec = lround(((secs - floor(secs))*1000000.0));
178
// wait until socket is writeable
179
err = select(s+1,NULL,&ff,NULL,&tv);
184
socklen_t len=sizeof(int);
185
if (getsockopt(s,SOL_SOCKET,SO_ERROR,&err,&len) == -1) {
193
send_file(int s,string fname)
195
// send_file() tries to send a file through a socket. it's presumed
196
// that the process on the other end of the socket is already
197
// expecting a file to be sent (i.e., is calling receive_file).
200
FILE *fp=fopen(fname.c_str(),"r");
203
if (fstat(fileno(fp),&st)) {
208
int filesize=st.st_size;
211
sprintf(buf,"send %s %d",fname.c_str(),filesize);
212
if (safe_send(s,buf,strlen(buf)+1,10.0)) {
217
int bytestosend=filesize;
219
while(bytestosend>0) {
220
packetsize=(F_BUFSIZE>bytestosend?bytestosend:F_BUFSIZE);
222
fread(buf,1,packetsize,fp);
224
if (safe_send(s,buf,packetsize,10.0)) {
228
bytestosend-=packetsize;
230
if (safe_recv(s,buf,F_BUFSIZE,10.0)<0)
233
if ((string)buf=="ACK")
239
receive_file(int s,string fname,int filesize)
241
FILE *fp=fopen(fname.c_str(),"w");
246
int packetsize,cnt=0,total=0;
249
if ((cnt=safe_recv(s,buf,F_BUFSIZE,10.0))<0) {
254
cnt=fwrite(buf,1,cnt,fp);
260
if (safe_send(s,buf,packetsize,10.0)) {