I wrote a module for asterisk that needs to communicate to a service request information an return it, but for some reason my socket does not connect at all. When I telnet to the service it works fine, but I can not figure out why the it returns a -1 in the module
This is the code in my module
int SocketQuery(char buffer[BUFFSIZE],char *qrystr){
int sock;
struct sockaddr_in eserver;
int sockres = 0;
unsigned char receiving = 1;
memset(sendbuff,0,sizeof(sendbuff));
/* Create the TCP socket */
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
ast_log(LOG_ERROR,"Failed to create socket for LCRROUTER");
return -1;
}
/* Construct the server sockaddr_in structure */
memset(&eserver, 0, sizeof(eserver)); /* Clear struct */
eserver.sin_family = AF_INET; /* Internet/IP */
eserver.sin_addr.s_addr = inet_addr(IP); /* IP address */
eserver.sin_port = htons(port); /* server port */
/* Establish connection */
ast_log(LOG_NOTICE,"LCRROUTER - Connection to %s on port %s\n", IP, port);
sockres = connect(sock,
(struct sockaddr *) &eserver,
sizeof(eserver));
if (sockres < 0) {
ast_log(LOG_ERROR,"LCRROUTER - Failed to connect with server on %s:%s. Error Code %d", IP,port,sockres);
return -1;
}
sockres returns -1. Do I miss something?
You can use
tcpdump port YOUR_PORT_HERE -v -s0
In that form it will show you all packets sent via socket.
Related
I have an application installed locally (not developed by me), which broadcasts UDP packets every second.
Reading the packets from my application (developed in C++ in Windows) which also is locally installed, works fine.
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOK = WSAStartup(version, &data);
SOCKET serverIn = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
sockaddr_in serverHint;
serverHint.sin_addr.S_un.S_addr = INADDR_ANY;
serverHint.sin_family = AF_INET;
serverHint.sin_port = htons(UDP_RECEIVE_PORT);
bind(serverIn, (sockaddr*)&serverHint, sizeof(serverHint));
sockaddr_in client;
int clientSize = sizeof(client);
int RECIEVE_BUFFER_SIZE = 65507;
char* recieveBuffer = new char[RECIEVE_BUFFER_SIZE];
while(updating)
{
int bytesIn = recvfrom(serverIn, recieveBuffer, RECIEVE_BUFFER_SIZE, 0, (sockaddr*)&client, &clientSize);
}
closesocket(serverIn);
WSACleanup();
But I recently noticed while I was testing some code, while my app was running, that the bind(...)
function returned an error code of 10048 (WSAEADDRINUSE). Hence, it seems the first client bound to listen for the UDP packets is the only one who can listen, and the other clients is unable to read the broadcasted UDP packets.
So then I added the SO_REUSEADDR option before calling the bind(...) function to be able to bind successfully to the socket:
BOOL bOptVal = TRUE;
int bOptLen = sizeof(BOOL);
setsockopt((SOCKET)serverIn, SOL_SOCKET, SO_REUSEADDR, (char*)&bOptVal, bOptLen);
That works, but the recvfrom(...) function then does not recieve any data at all! I guess it waits for the other client to close its socket.
Next solution is to initialize the socket with SOCK_RAW instead.
The above option SO_REUSEADDR is now not needed, and remove it:
SOCKET serverIn = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
This works, I can read the data now! Though, Windows now requires the adminstrator rights for my application. Also I do recieve the UDP information in the data which I do not need.
Is there any better method to do this without requiring administrator rights, any possibility to discard the header information in the buffer?
Below is a little program I wrote to demonstrate that IPv4 UDP broadcast can and does work as expected under Windows (i.e. without requiring raw-sockets or Administrator privileges).
Run it with the command line argument "server" and it will send out one broadcast UDP packet per second.
Then also run several more instances of the same program, with no command line arguments, to receive the UDP packets and print a line of text to stdout whenever they do. The expected behavior should look like this:
As for why it's not working for you -- one possible guess is that your UDP-packet-sending program is actually sending out unicast UDP packets rather than broadcast. If that's the case, then I would expect that only one client program would receive packets (even if multiple clients are bound to the same port). A network trace tool like Wireshark might be able to help you determine if the UDP packets being sent are broadcast or unicast.
Anyway, here's the code:
#include <stdio.h>
#include <ws2tcpip.h>
#pragma comment(lib,"WS2_32")
static int BindUDPSocket(SOCKET sock, unsigned short port, bool allowPortSharing)
{
if (sock == INVALID_SOCKET) return -1;
if (allowPortSharing)
{
const BOOL trueValue = true;
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &trueValue, sizeof(trueValue)) < 0) return -1;
}
struct sockaddr_in bindAddr; memset(&bindAddr, 0, sizeof(bindAddr));
bindAddr.sin_family = AF_INET;
bindAddr.sin_addr.s_addr = INADDR_ANY; // aka 0.0.0.0
bindAddr.sin_port = htons(port);
return bind(sock, (struct sockaddr *) &bindAddr, sizeof(bindAddr));
}
int main(int argc, char ** argv)
{
WSADATA data;
WORD version = MAKEWORD(2, 2);
(void) WSAStartup(version, &data);
const unsigned short TEST_PORT = 12345;
SOCKET sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock<0) {printf("socket() failed\n"); exit(10);}
if ((argc > 1)&&(strcmp(argv[1], "server") == 0))
{
if (BindUDPSocket(sock, 0, false)<0) {printf("BindUDPSocket() failed for server\n"); exit(10);}
const BOOL allowBroadcast = true;
if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (const char *) &allowBroadcast, sizeof(allowBroadcast)) < 0)
{
printf("setsockopt(SO_BROADCAST) failed\n");
exit(10);
}
const char buf[] = {0x01, 0x02, 0x03, 0x04}; // dummy data
struct sockaddr_in toAddr; memset(&toAddr, 0, sizeof(toAddr));
toAddr.sin_family = AF_INET;
toAddr.sin_addr.s_addr = INADDR_BROADCAST; // aka 255.255.255.255
toAddr.sin_port = htons(TEST_PORT);
printf("Sending outgoing broadcast UDP sockets on port %u, once per second\n", TEST_PORT);
while(true)
{
if (sendto(sock, buf, sizeof(buf), 0, (const sockaddr *) &toAddr, sizeof(toAddr)) == sizeof(buf))
{
printf("Sent %zu bytes of broadcast UDP data\n", sizeof(buf));
}
else printf("sendto() failed!\n");
Sleep(1000); // wait 1 second
}
}
else
{
if (BindUDPSocket(sock, TEST_PORT, true)<0) {printf("BindUDPSocket() failed for client\n"); exit(10);}
printf("Waiting to receive incoming broadcast UDP sockets on port %u\n", TEST_PORT);
while(true)
{
char buf[1024];
const int ret = recv(sock, buf, sizeof(buf), 0L);
printf("Received %i bytes of incoming UDP data\n", ret);
}
}
}
I am trying to make a "curl" client that can send requests to servers in C.
I've done creating a TCP socket (using slides from college, tested):
int connect_to_host(char * hostname, int port) {
// AF_INET: create socket that uses IPv4; SOCK_STREAM: type of sequenced, reliable
// 2-way connection-based byte streams ~ TCP (as opposed to datagrams ~ UDP)
int socket_fd;
struct sockaddr_in server_addr;
struct hostent * hp;
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
return -1; // remember to broadcast error, saved in errno (extern int errno)
}
// geting address (contained in struct hostent) from DNS
if ((hp = gethostbyname(hostname)) == NULL) {
return -2; // can't find hostname from DNS
}
// per documentation, must zero out bytes in the 'server' socket address before filling values
bzero((char *)&server_addr, sizeof(server_addr));
// filling necessary values of the 'server' socket address
server_addr.sin_family = AF_INET; // using IPv4
server_addr.sin_port = htons(port); // assign port value, remember to change int (host order byte)
// to network order byte. htons = host-to-network-short (short int)
bcopy((char *)hp->h_addr_list[0], (char *)&server_addr.sin_addr.s_addr, hp->h_length); // IP address, got from DNS
if (connect(socket_fd, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0) {
return -1; // error, as above
}
return socket_fd;
}
And created a TLS-version-flexible SSL/TLS context:
SSL_CTX * init_CTX() {
SSL_METHOD * method;
SSL_CTX * ctx;
OpenSSL_add_all_algorithms(); // Load cryptos, et.al.
SSL_load_error_strings(); // Bring in and register error messages
method = TLS_client_method(); // create new client-method instance
if ((ctx = SSL_CTX_new(method)) == NULL) {; // create new context
return NULL;
}
return ctx;
}
My next step is to create an SSL connection state and "bind" it with the file descriptor return by the TCP function (connect_to_host()) above. Then I will try to make SSL_connect()
if (*tls_mode == 1) {
ctx = init_CTX();
ssl = SSL_new(ctx); // create new SSL connection state
SSL_set_fd(ssl, clientfd); // bind socket descriptor to ssl state
if (SSL_connect(ssl) == -1) {
printf("SSL connection failed\n");
ERR_print_errors_fp(stderr);
return -1;
}
printf("debug tls: connect\n");
if (show_cert) SSL_show_certs(ssl);
}
At this point I receive the error in the title. I have checked stackoverflow and places but I don't see questions using C and the OpenSSL library. If anyone can give me a hint, I would really appreciate it.
So for anyone who checks back on this later, I made a mistake with my port number, and connect to port 80 instead of 443, causing the error.
I have server that just connects to a client and right after that disconnects, while client tries to send an integer to a closed socket (scanf is to ensure server closese it first). I use send with MSG_NOSIGNAL and check for EPIPE but the flag is not set. I think result should have printed value of -1, or 0, but it is equal to 1, because I am writing on already closed socket. Can someone explain that?
Server Code:
#define QUEUE_LENGTH 5
#define PORT_NUM 10002
#define BUFFER_SIZE 512000
int main(int argc, char *argv[]) {
int sock, msg_sock;
struct sockaddr_in server_address;
struct sockaddr_in client_address;
socklen_t client_address_len;
sock = socket(PF_INET, SOCK_STREAM, 0); // creating IPv4 TCP socket
if (sock < 0)
syserr("socket");
server_address.sin_family = AF_INET; // IPv4
server_address.sin_addr.s_addr = htonl(
INADDR_ANY); // listening on all interfaces
server_address.sin_port = htons(PORT_NUM);
// bind the socket to a concrete address
if (bind(sock, (struct sockaddr *) &server_address,
sizeof(server_address)) < 0)
syserr("bind");
// switch to listening (passive open)
if (listen(sock, QUEUE_LENGTH) < 0)
syserr("listen");
printf("accepting client connections on port %hu\n",
ntohs(server_address.sin_port));
for (;;) {
client_address_len = sizeof(client_address);
msg_sock = accept(sock, (struct sockaddr *) &client_address,
&client_address_len);
if (msg_sock < 0)
syserr("accept");
printf("ending connection\n");
if (close(msg_sock) < 0) {
printf("ErrorClosingSocket\n");
break;
}
continue;
}
return 0;
}
Client code:
int sendSomething(void *to_send, int socket, uint32_t length) {
if (send(socket, to_send, length, MSG_NOSIGNAL) !=
length) {
if (errno == EPIPE) // Sending on closed connection
return 0;
return -1;
}
return 1;
}
int main(int argc, char *argv[]) {
int sock;
struct addrinfo addr_hints;
struct addrinfo *addr_result;
int err;
if (argc != 3)
fatal("Usage: %s host port\n", argv[0]);
// 'converting' host/port in string to struct addrinfo
memset(&addr_hints, 0, sizeof(struct addrinfo));
addr_hints.ai_family = AF_INET; // IPv4
addr_hints.ai_socktype = SOCK_STREAM;
addr_hints.ai_protocol = IPPROTO_TCP;
// argv[1] is localhost and argv[2] is 10002
err = getaddrinfo(argv[1], argv[2], &addr_hints, &addr_result);
if (err == EAI_SYSTEM) // system error
syserr("getaddrinfo: %s", gai_strerror(err));
else if (err != 0) // other error (host not found, etc.)
fatal("getaddrinfo: %s", gai_strerror(err));
// initialize socket according to getaddrinfo results
sock = socket(addr_result->ai_family, addr_result->ai_socktype,
addr_result->ai_protocol);
if (sock < 0)
syserr("socket");
// connect socket to the server
if (connect(sock, addr_result->ai_addr, addr_result->ai_addrlen) < 0)
syserr("connect");
freeaddrinfo(addr_result);
int result;
scanf("%d", &result);
uint16_t test;
test = htons(1);
result = sendSomething(&test, sock, sizeof(test));
printf("result:%d\n", result);
if (close(sock) < 0) {
printf("ErrorClosingSocket\n");
}
return 0;
}
Note: Fatal and Syserr are just for reporting errors
That's the way TCP works. When the server closes the socket, then a FIN is sent to the client. This only signals, that the server will not send any more data. It does not necessarily mean, that it does not want to receive more data.
Thus, the client can call send() on the socket without the OS reporting an error. If the server indeed closed the whole socket, then it will send a TCP reset packet as a response to incoming data indicating that condition. Now, future operations on the socket (write/close) will indicate an error.
It is indeed possible for the server (or any peer) to only shutdown the connection half-way (the reading or the writing side) with the syscall shutdown(). If the server shuts down the connection for writing, the same thing happens on the network as if the server closed the whole connection with close(). It is the duty of a higher level protocol to determine, when a connection should be closed for each side.
If you want to make sure, that all data that you sent was indeed acknowledged by the peer, you can use the SO_LINGER socket option. But a more common way is, to make this sure as a part of the communication protocol, i.e. one part requests to shutdown the connection on a higher level (for example, the smtp QUIT command) and the peer reacts on it by closing the tcp connection.
I have an outside equipment that is suppose to send datas every second to my program computer (under linux). The documentation of this equipment says :
Ethernet interface with a fixed IP address of 192.168.0.40
The UDP ports used for the Ethernet interface is 4230
Destination : 192.168.0.20
So i tried to write the simpliest possible program to read these datas. My linux machine IP is set to 192.168.0.20 :
#define PORT 4230
#define BUFSIZE 72
struct sockaddr_in myaddr; /* our address */
struct sockaddr_in remaddr; /* remote address */
socklen_t addrlen = sizeof(remaddr); /* length of addresses */
int recvlen; /* # bytes received */
int fd; /* our socket */
unsigned char buf[BUFSIZE]; /* receive buffer */
/* create a UDP socket */
if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
{ perror("cannot create socket\n"); return 0; } /* bind the socket to any valid IP address and a specific port */
memset((char *)&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(PORT);
if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0)
{ perror("bind failed"); return 0; }
/* now loop, receiving data and printing what we received */
for (;;)
{
printf("waiting on port %d\n", PORT);
recvlen = recvfrom(fd, buf, BUFSIZE, 0, (struct sockaddr *)&remaddr, &addrlen);
printf("received %d bytes\n", recvlen);
if (recvlen > 0)
{
buf[recvlen] = 0;
printf("received message: \"%s\"\n", buf);
}
}
But i'm blocked at recvfrom(), never receiving datas ... What i'm doing wrong ? I tried to change INADDR_ANY to the right IP but still the same ...
Thank you.
EDIT/UPDATE : Using wireshark I have more information about the UDP packet from the outside equipment :
Source 192.168.0.40 Destination 192.168.0.20
Source port 4230 Dest port 2430
Maybe i need to precise the dest port on the code ? But i don't know where and how to do this ...
The packet is destined for port 2430, but your program is waiting for input on port 4230 (set with the PORT macro in your code).
The port should be the port you want input to be received on, not the source port on the other end of the communication.
So change the PORT macro to be 2430.
im using socket in c and got success on send/recv. however, the problem is when my server crashes, the client has to reconnect the server (server runs after some time).
so here what i did:
create a socket
connect
recv/send
if recv size == 0
go to step 2.
this algorithm is not working for me.
is there any ideas?
code:
int initSocket(char *servIP, unsigned short serverPort)
{
portNum = serverPort;
ipAddr = servIP;
/* Socket descriptor */
struct sockaddr_in echoServAddr; /* Echo server address */
if ((sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
printf("socket() failed");
bConnected = -1;
return -1;
}
/* Construct the server address structure */
memset(&echoServAddr, 0, sizeof(echoServAddr)); /* Zero out structure */
echoServAddr.sin_family = AF_INET; /* Internet address family */
echoServAddr.sin_addr.s_addr = inet_addr(ipAddr); /* Server IP address */
echoServAddr.sin_port = htons(portNum); /* Server port */
struct timeval timeout;
timeout.tv_sec = 0;
timeout.tv_usec = 20000;
if (setsockopt (sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
error("setsockopt failed\n");
/*if (setsockopt (sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
error("setsockopt failed\n");
*/
/* Establish the connection to the echo server */
if (connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr)) < 0)
{
printf("connect() failed\n");
bConnected = -1;
//close(sock);
return -1;
}
bConnected = 0;
return 0;
}
--------------- if server crashes ------------
if(recv_size == 0)
{
// server crashed
while(initSocket(ipAddr, portNum) < 0)
{
printf("IP : %s\v", ipAddr);
printf("Port : %d\v", portNum);
}
}
-----------------------------
create a socket
connect
recv/send if recv size == 0 go to step 2.
You cannot re-connect a TCP socket, you have to create a new one.
You'd also want to handle the case where recv or send errors.
So this have to be:
create a socket
connect
recv/send
if recv returns <= 0 or send returns -1 (and it's not a timeout): close socket, goto step 1
Though, it seems your code already does all these steps, and not just repeating step 2 and 3, so it's a bit unclear what's the actual problem you are observing.
In addition, your initSocket() code does not close() the socket when connect() fails, so you'll easily leak sockets and run out of file descriptors in less than a second once the server fails,
you have to close() the socket you just created if you're not going to use it.