So I'm passing an argument to my main which is an IP as char* name ipStr.
Then I'm initialising a variable to hold the length of it before calling sendto():
sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
char buffer[8];
socklen_t ipLen = sizeof(ipStr);
res = sendto(sock, buffer, sizeof(buffer), 0,
(struct sockaddr*) &ipStr, ipLen);
Yet I'm still getting Invalid argument as a returned error.
I'm getting no compile errors with g++ so I'm not sure where the problem is.
EDIT
I noticed I hadn't deleted sizeof before ipLen, changed the above and still getting Invalid argument.
Your sockaddr is probably wrong, it's a struct with a binary representation of the address and some other data in it. It's a sockaddr_in cast to a sockaddr.
Try:
struct sockaddr_in ip4addr;
ip4addr.sin_family = AF_INET;
ip4addr.sin_port = htons(1234);
addrDest.sin_addr.s_addr = inet_addr("1.2.3.4");
socklen_t ipLen = sizeof(ipStr) returns the size of ipStr data type, not the length of the string it points to. The data type of ipStr is char *, and sizeof(ipStr)therefore yields 8 (or 4 on 32 bit systems). So your parameter will probably not be interpreted correctly.
Use socklen_t ipLen = strlen(ipStr) instead.
Related
I have written a simple UDP server. Well, naturally I use recvfrom() function somewhere in it. I have searched the net for it, and found that it is caused by the buffer overflow. Is this true? But I can't figure why my code fails and throws the same error, here is the part associated with recvfrom():
char messageFromClient[1024] = {0};
returnStatus = recvfrom(udpSocket, &messageFromClient, strlen(messageFromClient), 0, (struct sockaddr*)&udpSocket,
&addrlen);
The file descriptor before invocation of recvfrom() is 3 but when I call it, it changes to -187301886
Your code fails because you specify 0 receive buffer size and you pass the socket file descriptor as the peer address argument (which overwrites its value):
Fix:
char messageFromClient[1024];
sockaddr_in addr;
socklen_t addrlen = sizeof addr;
ssize_t received = recvfrom(udpSocket, messageFromClient, sizeof messageFromClient, 0, (sockaddr*)&addr, &addrlen);
My IDE: xCode, OS X 10.10.4
int s = socket(AF_INET, SOCK_DGRAM, 0);
bool bc = true;
int ret = setsockopt(s, SOL_SOCKET, SO_BROADCAST, (const void*)&bc, sizeof(bool));
if(ret < 0){
perror("set opt err:");
}
sockaddr_in tarAddr;
memset(&tarAddr, 0, sizeof(sockaddr_in));
tarAddr.sin_family = AF_INET;
tarAddr.sin_port = htons(5000);
tarAddr.sin_addr.s_addr = INADDR_BROADCAST;
char szMsg[100] = {0};
strcpy(szMsg, "hello");
int len = sizeof(sockaddr);
ret = sendto(s, szMsg, strlen(szMsg), 0, (sockaddr*)&tarAddr, len);
if(ret < 0){
perror("sendto err:");
}
close(s);
The above code is about send udp message to broadcast, but the result info is:
set opt err: Invalid argument
sendto err: Permission denied
and the same code go fine in vc++/windows.
Maybe the argument sizeof(bool) returns an invalid value. As you can see in the following link, it is not defined that sizeof(bool)should deliver 1.
Is sizeof(bool) defined?
I also think that you don't have to cast the pointer in the function call. It would be enough only to have the &.
Can you provide some code of the sendto()function to determine the other error?
I changed bc to int and this solve the problem
As has been insinuated, your optval is wrong.
From the socket manpage:
The socket options listed below can be set by using setsockopt(2) and
read with getsockopt(2) with the socket level set to SOL_SOCKET for
all sockets. Unless otherwise noted, optval is a pointer to an int.
You're giving it a pointer to a bool instead.
Fortunately, the function is able to detect this (possibly sizeof(bool) differs from sizeof(int) on your platform, or otherwise its reinterpreting a bool as an int simply results in a value it doesn't recognise; it's UB anyway), so you get a nice error telling you that your argument is wrong.
Remember, the function doesn't know the type of your data (as it gets a void*), so even if it wanted to be able to accept an int or a bool or llama it would have no way of doing so.
Hi
I have a problem with giving a name to socket by a program parameter.
I tried do it in many ways, some conversions (strcpy function)etc. but in the best option it gives me a one letter from my name. How can I convert/put it into that structure?
void socket_out(char* name)
{
int listfd;
int connfd;
listfd = socket(AF_UNIX, SOCK_STREAM, 0);
if(listfd == -1)
exit(-1);
struct sockaddr saddr = {AF_UNIX, name};
socklen_t saddrlen = sizeof(struct sockaddr) + 6;
bind(listfd, &saddr, saddrlen);
And error:
error: invalid conversion from ‘char*’ to ‘char’ [-fpermissive]
struct sockaddr saddr = {AF_UNIX, name};
Sorry, I just realized my previous answer was out of topic, as you seem to use Unix Domain Sockets, not TCP/IP sockets.
The problem is that you should never use struct sockaddr directly, but rather one of its "specializations", in this case struct sockaddr_un, and then cast it at the last minute. Have a look at the following example:
unsigned int s, s2;
struct sockaddr_un local, remote;
int len;
s = socket(AF_UNIX, SOCK_STREAM, 0);
local.sun_family = AF_UNIX;
strcpy(local.sun_path, "/home/beej/mysocket");
unlink(local.sun_path);
len = strlen(local.sun_path) + sizeof(local.sun_family);
bind(s, (struct sockaddr *)&local, len);
Taken from the excellent Beej's Guide to Unix IPC: http://beej.us/guide/bgipc/output/html/multipage/unixsock.html
you are tying to initialize a structure there, but the second parameter is not of type char*, but of type char[].
See the definition for struct sockaddr:
The <sys/socket.h> header shall define the sockaddr structure that includes at least the following members:
sa_family_t sa_family Address family.
char sa_data[] Socket address (variable-length data).
To get around that, you have to use strcpy/strncpy for the second parameter:
struct sockaddr saddr;
saddr.sun_family = AF_UNIX;
strncpy(saddr.sun_path, name, UNIX_PATH_MAX);
addr.sun_path[UNIX_PATH_MAX - 1] = '\0';
in code :
if ((host = (struct hostent*) gethostbyname(address) ) == 0) // address is a string
I've got warning when cross compiling (generic arm architecture) on 4.5.x gcc :
(.text+0x1558): warning: gethostbyname is obsolescent, use getnameinfo() instead.
getnameinfo is:
int WSAAPI getnameinfo(
__in const struct sockaddr FAR *sa,
__in socklen_t salen,
__out char FAR *host,
__in DWORD hostlen,
__out char FAR *serv,
__in DWORD servlen,
__in int flags
);
And it got more parameters... And I'm confused with it, I just need it work as gethostbyname were working. What parameter to pass to keep it simple stupid as it was with gethostbyname?
Finally here is my try:
struct sockaddr_in servAddr;
struct hostent *host; /* Structure containing host information */
/* open socket */
if ((handle = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
return LILI_ERROR;
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = inet_addr(address.ptr());
servAddr.sin_port = htons(port);
char servInfo[NI_MAXSERV];
if ( ( host = (hostent*) getnameinfo(
(struct sockaddr *) &servAddr
,sizeof (struct sockaddr)
,address.ptr(), address.size()
,servInfo, NI_MAXSERV
,NI_NUMERICHOST | NI_NUMERICSERV ) ) == 0)
return LILI_ERROR;
if (::connect(handle, (struct sockaddr *) &servAddr, sizeof(servAddr)) < 0)
return LILI_ERROR;
It compiles well and no segmentation fault on start up but I can't connect my server with it :(
gethostbyname() does a name→IP lookup. It should be replaced with getaddrinfo(), which can do the same.
This means the warning is completely wrong. getnameinfo() is the replacement of gethostbyaddr(), both for IP→name lookups. The reverse.
name→IP: gethostbyname(), getaddrinfo()
IP→name: gethostbyaddr(), getnameinfo()
The newer functions can do more: they handle IPv6 and can translate strings like 'http' to 80 (port). In the future they can also determine if e.g. TCP should be used for the service in question or SCTP. The interface is ready.
Beej's explains it pretty good. gethostbyname() does not works well with IPV6 and thus you should use getnameinfo() instead. All you have to do is to fill in the required informations, i.e.
getnameinfo(
&sa, // Pointer to your struct sockaddr
sizeof sa, // Size of this struct
host, // Pointer to hostname string
sizeof host, // Hostname string buffer length
service, // Pointer to service name string
sizeof service, // Service name string buffer length
0 // No flags given
);
Edit: After some research, I've found that
getnameinfo(&sa, sizeof(sa), hostname, size_hostname, NULL, 0, 0);
should be sufficient.
Edit #2 I've noticed you are trying to use the return value of getnameinfo as hostname. But that is not correct, the hostname is saved within the provided host pointer. The return value indicates whether the operation was sufficient. Also have a look at the man page.
I don't normally go to stackoverflow for sigsegv errors, but I have done all I can with my debugger at the moment.
The segmentation fault error is thrown following the completion of the function. Any ideas what I'm overlooking? I suspect that it is due to the casting of the sockaddr to the sockaddr_in, but I am unable to find any mistakes there. (Removing that line gets rid of the seg fault -- but I know that may not be the root cause here).
// basic setup
int sockfd;
char str[INET_ADDRSTRLEN];
sockaddr* sa;
socklen_t* sl;
struct addrinfo hints, *servinfo, *p;
int rv;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
// return string
string foundIP;
// setup the struct for a connection with selected IP
if ((rv = getaddrinfo("4.2.2.1", NULL, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return "1";
}
// loop through all the results and make a socket
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("talker: socket");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "talker: failed to bind socket\n");
return "2";
}
// connect the UDP socket to something
connect(sockfd, p->ai_addr, p->ai_addrlen); // we need to connect to get the systems local IP
// get information on the local IP from the socket we created
getsockname(sockfd, sa, sl);
// convert the sockaddr to a sockaddr_in via casting
struct sockaddr_in *sa_ipv4 = (struct sockaddr_in *)sa;
// get the IP from the sockaddr_in and print it
inet_ntop(AF_INET, &(sa_ipv4->sin_addr), str, INET_ADDRSTRLEN);
printf("%s\n", str);
// return the IP
return foundIP;
}
It doesn't look like you ever initialize the pointer sa to point at a valid sockaddr (or sockaddr_in) object.
If you replace
sockaddr* sa;
with
sockaddr addr;
and replace all uses of sa with &addr you should be in better shape.
The same is also true of sl. At least according to the documentation for my getsockname the socklen_t* parameter needs to point at a valid socklen_t object initialized to the size in bytes of the address buffer.
E.g.
socklen_t slen = sizeof addr;
and use &slen instead of sl.
It looks to me like you don't ever set up the sa pointer to actually point at anything. Commenting out the line "struct sockaddr_in *sa_ipv4 = (struct sockaddr_in *)sa;" should cause a compile error, so I guess I can see how not being able to compile your program would also cause it to not segfault - hard for a non-existent binary to crash :)
just to add, valgrind is pretty useful in detecting uninitialized pointers or for that matter any pointer related errors.
You did not allocate sa before passing it to getsockname, so you effectively passed in some garbage pointer value there. It needs to be:
struct sockaddr_in sa;
socklen_t sl;
...
getsockname(sockfd, (struct sockaddr*)&sa, &sl);
...