[prev in list] [next in list] [prev in thread] [next in thread]
List: freetds
Subject: Re: [freetds] connect(2) for UDP
From: "James K. Lowden" <jklowden () freetds ! org>
Date: 2008-12-18 23:40:43
Message-ID: 20081218184043.557bc60b.jklowden () freetds ! org
[Download RAW message or body]
Peter Deacon wrote:
>
> UDP has no concept of connection. Each message stands alone.
>
> If the server binds to all interfaces and there are multiple interfaces
> capable of reaching the client the source address of messages from the
> server should be concidered random/determined by the routing system.
Not only are you right, you're right. I even read as much after posting
my message.
And I found a server that answers on a different interface! :-) And,
using a combination of techniques, I seem to have something that works.
1. If I connect only, I miss answers from other interfaces.
2. If I bind only, I don't get ECONNREFUSED, only a timeout. Perhaps
that's me or my implementation.
Therefore, I do both, using two sockets, of course. select(2) tells me
which one is ready, and, mirabile dictu, I get what I want: success,
timeout, or ECONNREFUSED.
== code ==
fd_set fds;
FD_ZERO(&fds);
FD_SET(s1, &fds);
FD_SET(s2, &fds);
struct timeval timeout;
bzero(&timeout, sizeof(timeout));
timeout.tv_sec = 5;
timeout.tv_usec = 0;
cout << "reading from " << hostname << ":" << port << " ... " << flush;
if( (erc = select(s2 + 1, &fds, NULL, NULL, &timeout)) == -1 ) {
perror("select(2) failed");
return 1;
}
if( 0 == erc ) {
cerr << "timed out, sorry.\n";
return 1;
}
cout << erc << " fd ready on " << flush;
int s;
char buffer[2048];
if( FD_ISSET(s1, &fds) ) {
s = s1;
cout << "connected ... " << flush;
}
if( FD_ISSET(s2, &fds) ) {
s = s2;
cout << "bound ... " << flush;
}
while( (erc = read(s, &buffer, sizeof(buffer))) == -1 ) {
perror("could not read");
return 1;
}
cout << "done. (read " << erc << " bytes)\n" << flush;
== edoc ==
Data arrive on the bound port. Errors are detected on the connected port:
== output ==
$ ./connect_udp -h db03 -p 1434
address of db03 is 10.10.10.10
binding local UDP socket ... done
sending to db03:1434 ... done. (sent 1)
connecting UDP socket to db03:1434 ... done
writing to db03:1434 ... done. (wrote 1)
reading from db03:1434 ... 1 fd ready on bound ... done. (read 411 bytes)
./connect_udp -h localhost -p 1434
address of localhost is 127.0.0.1
binding local UDP socket ... done
sending to localhost:1434 ... done. (sent 1)
connecting UDP socket to localhost:1434 ... done
writing to localhost:1434 ... done. (wrote 1)
reading from localhost:1434 ... 1 fd ready on connected ...
could not read: Connection refused
== tuptou ==
Too bad none of this is standardized. Standards? We don't need no
stinking standards!
That about wraps up the research. I think I'll file a bug report and see
if the project maintaner will update FreeTDS. Oh, wait....
Regards,
--jkl
["connect_udp.C" (application/octet-stream)]
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
extern int h_errno;
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <cassert>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;
enum modes {binding, connecting} mode = binding;
char lower( char c ) {
return tolower(c);
}
int
main( int argc, char *argv[] )
{
int s1, s2, ch, port = 0, erc;
sockaddr_in loc, svr;
string hostname;
while( (ch = getopt(argc, argv, "c:h:p:")) != -1 ) {
switch (ch) {
case 'c': {
string option(optarg);
transform(option.begin(), option.end(), option.begin(), lower);
if( option == "connect" ) {
mode = connecting;
} else {
if( option != "bind" ) {
cerr << "-c {bind|connect}\n";
return 1;
}
}
}
break;
case 'h':
hostname = optarg;
break;
case 'p': {
stringstream s(optarg);
s >> port;
assert(port != 0);
}
break;
default:
exit(1);
}
}
if( hostname.empty() ) {
cerr << "need hostname\n";
return 1;
}
if( port == 0 ) {
cerr << "need port\n";
return 1;
}
hostent *ent = gethostbyname(hostname.c_str());
if( !ent ) {
herror(hostname.c_str());
return 1;
}
memcpy( &svr.sin_addr.s_addr, ent->h_addr_list[0], sizeof(svr.sin_addr.s_addr) );
cout << "address of " << hostname << " is " << inet_ntoa( \
*reinterpret_cast<in_addr*>(&svr.sin_addr.s_addr) ) << endl;
svr.sin_family = PF_INET;
svr.sin_port = htons(port);
if( (s1 = socket(PF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("could not create socket");
return 1;
}
if( (s2 = socket(PF_INET, SOCK_DGRAM, 0)) < 0 ) {
perror("could not create local socket");
return 1;
}
unsigned long ioctl_nonblocking = 1;
if( (erc = ioctl(s1, FIONBIO, &ioctl_nonblocking)) < 0) {
perror("could not set nonblocking mode");
return 1;
}
if( (erc = ioctl(s2, FIONBIO, &ioctl_nonblocking)) < 0) {
perror("could not set nonblocking mode");
return 1;
}
char cmd[3] = { 0x03, '\0' };
if( 1434 != port )
strcpy(cmd, "A\n");
if( mode == binding ) {
loc.sin_addr.s_addr = INADDR_ANY;
loc.sin_port = htons((short) 4341);
loc.sin_family = PF_INET;
cout << "binding local UDP socket ... " << flush;
if (bind(s2, (struct sockaddr *) &loc, sizeof(loc)) < 0) {
perror("failed");
return 1;
}
cout << "done\n";
cout << "sending to " << hostname << ":" << port << " ... " << flush;
if( (erc = sendto(s2, &cmd, strlen(cmd), 0, (const sockaddr*)&svr, sizeof(svr))) == \
-1 ) { perror("failed");
return 1;
}
cout << "done. (sent " << erc << ")\n";
}
cout << "connecting UDP socket to " << hostname << ":" << port << " ... " << flush;
if( (erc = connect(s1, (const sockaddr*)&svr, sizeof(svr))) < 0 ) {
perror("failed");
return 1;
}
cout << "done\n";
cout << "writing to " << hostname << ":" << port << " ... " << flush;
if( (erc = write(s1, &cmd, strlen(cmd))) == -1 ) {
perror("failed");
return 1;
}
cout << "done. (wrote " << erc << ")\n";
fd_set fds;
FD_ZERO(&fds);
FD_SET(s1, &fds);
FD_SET(s2, &fds);
struct timeval timeout;
bzero(&timeout, sizeof(timeout));
timeout.tv_sec = 5;
timeout.tv_usec = 0;
cout << "reading from " << hostname << ":" << port << " ... " << flush;
if( (erc = select(s2 + 1, &fds, NULL, NULL, &timeout)) == -1 ) {
perror("select(2) failed");
return 1;
}
if( 0 == erc ) {
cerr << "timed out, sorry.\n";
return 1;
}
cout << erc << " fd ready on " << flush;
int s;
char buffer[2048];
if( FD_ISSET(s1, &fds) ) {
s = s1;
cout << "connected ... " << flush;
}
if( FD_ISSET(s2, &fds) ) {
s = s2;
cout << "bound ... " << flush;
}
while( (erc = read(s, &buffer, sizeof(buffer))) == -1 ) {
perror("could not read");
return 1;
}
cout << "done. (read " << erc << " bytes)\n" << flush;
for( char *p=buffer; p < buffer + erc; p++ ) {
if( *p == ';' )
*p = '\n';
if( isprint(*p) || isspace(*p) )
putchar(*p);
}
}
_______________________________________________
FreeTDS mailing list
FreeTDS@lists.ibiblio.org
http://lists.ibiblio.org/mailman/listinfo/freetds
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic