Write a C socket inside a function - c

I'm new in sockets and I don't know if its possible to do what I'm trying. First of all, I've looked for more info in Google and in stackoverflow but I haven't found anything :(
Now I explain my problem. I have created client socket (with the functions socket y connect) in the main function with no problem. But then I call a function called sendframe() thet I've created, where I do some stuff and then I use the write function to put a message in the socket. The problem here is that I dont know why the write function gives an error (returns -1). I think the problem is that I haven't passed correctly the socket file descriptor, but I'm not sure (I'm not convinced that using only the file descriptor allows me to write in the socket...)
Here is a snippet of what I'm trying to do:
#include ...
void sendframe(int sockfd);
void main(void) {
//// Open the socket
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("open socket erorr\n");
server = gethostbyname("192.168.20.155");
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = 1414;
serv_addr.sin_addr = *((struct in_addr *) server->h_addr);
bzero(&(serv_addr.sin_zero),8);
if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr))==-1)
error("connect error\n");
exit(-1);
// ..... More code.....
// Send frame
sendframe(&sockfd);
}
void sendframe(int sockfd)
{
// Some stuff...
char *frame
int num = write(sockfd,frame,strlen(frame));
}
Probably the answer is so easy, but I'm new in this. Any clue?

sendframe(&sockfd); should be sendframe(sockfd); as sendframe expects an int, not int *.

Related

custom tcp over udp socket bind

I am trying to make basic reliable connection over udp. I have defined the custom bind function which takes same kind of arguments as TCP bind but in my function during passing parameters I got the error message as below:
bind() failed: Address family not supported by protocol
I have defined the r_bind function in one file and is accessed from next file. The function is as below:
int r_bind(int sockfd, struct sockaddr *addr,socklen_t addrlen){
return bind(sockfd, (struct sockaddr*) &addr, addrlen);
}
typedef struct brp_socket{
int sockfd;
struct sockaddr_in brp_serveraddr;
struct sockaddr_in brp_useraddr;
}brp_socket;
I have made call from user1.c file. The socket was created successfully but during binding I got the error. I have made the following function call.
brp_socket socket_list[BRP_MAX_SOCKET];
int socket_index = 0;
int servSock; // Socket descriptor for server
servSock = r_socket(AF_INET, SOCK_BRP, 0)
socket_list[socket_index].sockfd = servSock;
memset(&socket_list[socket_index].brp_serveraddr, 0, sizeof(socket_list[socket_index].brp_serveraddr)); // Zero out structure
socket_list[socket_index].brp_serveraddr.sin_family = AF_INET; // IPv4 address family
socket_list[socket_index].brp_serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); // Any incoming interface
socket_list[socket_index].brp_serveraddr.sin_port = htons(servPort); // Local port
if (r_bind(socket_list[socket_index].sockfd, (struct sockaddr*)&(socket_list[socket_index].brp_serveraddr), sizeof(socket_list[socket_index].brp_serveraddr)) < 0)
#define SOCK_BRP 1
int r_socket(int domain, int type, int protocol){
if(type == 1)
{
return socket(domain,SOCK_DGRAM,protocol);
}
}
Here BRP_SOCK is custom made protocol type.
Can anyone suggest me where I made the mistake?

C unix domain sockets, recvfrom() doesn't set struct sockaddr* src_addr

I'm writing an application that listens for UDP packets over a unix domain socket. Consider the following code block.
int sockfd;
struct sockaddr_un servaddr;
sockfd = socket(AF_LOCAL, SOCK_DGRAM, 0);
if(sockfd < 0)
{
perror("socket() failed");
}
unlink(port);
bzero(&servaddr, sizeof(servaddr));
servaddr.sun_family = AF_LOCAL;
strcpy(servaddr.sun_path, port);
if(bind(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)
{
perror("bind() failed");
close(sockfd);
}
int n;
struct sockaddr_un cliaddr;
socklen_t len = sizeof(cliaddr);
discovery_msgs client_message;
bzero(&client_message, sizeof(client_message));
// Wait for a message to be received
n = recvfrom(sock_fd, &client_message, sizeof(client_message), 0,
(struct sockaddr *) &cliaddr, &len);
// At this point n = 560, client_message is filled with the expected data
//len = 0 and cliaddr has no information about the client that sent the data
Now the type of client_message isn't really important, I'm receiving a UDP packet and client_message contains all of the data I expect. The problem begins when I look at cliaddr and len after calling recvfrom. cliaddr is not modified by recvfrom like it normally is with normal network TCP/UDP and len is set to 0 after the call(which means recvfrom wrote no data to &cliaddr). I need the information in cliaddr to be populated with the unix domain path so I can send a response.
What am I doing wrong?
The solution is binding the socket on the client side when using Unix domain sockets. Otherwise the transient pathname created for sending the UDP packet immediately disappears after sendto(), which explains why the client's address information is not available on the server side.
See Stevens Network Programming page 419 or see this for an example client implementation that solves this issue: libpix.org/unp/unixdgcli01_8c_source.html
#include "unp.h"
int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_un cliaddr, servaddr;
sockfd = Socket(AF_LOCAL, SOCK_DGRAM, 0);
bzero(&cliaddr, sizeof(cliaddr)); /* bind an address for us */
cliaddr.sun_family = AF_LOCAL;
strcpy(cliaddr.sun_path, tmpnam(NULL));
Bind(sockfd, (SA *) &cliaddr, sizeof(cliaddr));
bzero(&servaddr, sizeof(servaddr)); /* fill in server's address */
servaddr.sun_family = AF_LOCAL;
strcpy(servaddr.sun_path, UNIXDG_PATH);
dg_cli(stdin, sockfd, (SA *) &servaddr, sizeof(servaddr));
exit(0);
}
Note: unp.h defines Bind() which is simply bind() with some error checking(commonly used throughout Stevens Network Programming). In the same manner, (SA *) is the equivalent to (struct sockaddr *).

connect() function fails when passing sockaddr_in as argument

I have been at this for an ungodly amount of time, so I really hope someone can provide me some keen insight as to what is going on.
I have the following main function:
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
int main(int argc, char **argv) {
char *serv_IP;
in_port_t serv_port;
int sock;
struct sockaddr_in serv_addr;
serv_IP = argv[1];
serv_port = atoi(argv[2]);
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
fprintf(stderr, "Failed to create TCP socket\r\n");
exit(1);
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
if (inet_pton(AF_INET, serv_IP, &serv_addr.sin_addr.s_addr) == 0) {
fprintf(stderr, "Invalid IP address\r\n");
exit(1);
}
serv_addr.sin_port = htons(serv_port);
if (connect(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
fprintf(stderr, "Failed to connect to serv\r\n");
exit(1);
}
else {
printf("You're connected!\n);
}
close(sock)
return 0;
}
Now, this code works just fine. However, what I want to do is to replace the call to connect() with a helper function call to something like this:
void function(int sock, struct sockaddr_in *serv_addr) {
if (connect(sock, (struct sockaddr *) serv_addr, sizeof(serv_addr)) < 0) {
printf("Server IP = %s\n", inet_ntoa(serv_addr->sin_addr));
printf("Server port = %d\n", ntohs(serv_addr->sin_port));
fprintf(stderr, "Failed to connect to server\r\n");
exit(1);
}
else {
// Do other stuff
}
}
I remove the call to connect() from main() and replace it with the function call:
function(sock, &serv_addr);
As soon as the function is called, the correct IP and port numbers are printed out, but I still fail to connect to my server. The only difference is, in my main function(), I preface serv_addr in the connect call with the & - i.e., connect(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) - to reference its address, and I don't do that in the helper function because the address of serv_addr is already being passed as an argument - i.e., connect(sock, (struct sockaddr *) serv_addr, sizeof(serv_addr)). It makes no difference if I add the &, just in case you were wondering.
So, with the &serv_addr being passed to function() seemingly correctly, as verified by me being able to print out the correct IP and port numbers, why is it that I can connect in main() but not when I pass the serv_addr struct as an argument to another function and call connect() from there?
Thanks in advance for any help!
sizeof(serv_addr) returns 16 when serv_addr is declared as sockaddr_in, but returns 4 (in 32bit) or 8 (in 64bit) when declared as sockaddr_in*. It is too small either way, AF_INET needs 16. Had you looked at errno when connect() failed, it would have told you that you were passing an invalid parameter value.
You need to use sizeof(sockaddr_in), either directly:
void function(int sock, struct sockaddr_in *serv_addr)
{
if (connect(sock, (struct sockaddr *) serv_addr, sizeof(struct sockaddr_in)) < 0)
Or indirectly via sizeof(*serv_addr):
void function(int sock, struct sockaddr_in *serv_addr)
{
if (connect(sock, (struct sockaddr *) serv_addr, sizeof(*serv_addr)) < 0)
That did it! Thank you very much for your quick response!! I never would have thought about the return of sizeof() as a potential problem with returning different sizes for actual values vs. pointers to values. Totally makes sense, though. And I just read about the errno.h header as well as how to use it.
The exact line that fixed it was:
if (connect(sock, (struct sockaddr *) serv_addr, sizeof(struct sockaddr_in)) < 0)
I was right about not needing the '&' in front of serv_add. You also need the "struct" in sizeof() or else it returns sockaddr_in as an undeclared variable.
Anyways, thanks again.
Now I can finally move on with my code.

bind() fails with windows socket error 10049

I try to make a client/server program in C with IPv6 and UDP. When the program binds the socket it return the WSAError 10049. I know that this is a problem with the adress name but don't see whats the problem. I hope someone can help.
struct sockaddr_in6 server, client;
SOCKET sock;
char buffer[BUFFERSIZE];
LPTSTR recvBuff[1024];
DWORD recvBuffLen = 1024UL;
int len = sizeof(client);
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(1,1);
WSAStartup(wVersionRequested, &wsaData);
sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock < 0)
error("Fehler beim Anlegen des Sockets");
server.sin6_family = AF_INET6;
server.sin6_port = htons(6000);
server.sin6_addr = in6addr_any;
if (bind(sock, (struct sockaddr *) &server, sizeof(server)) == -1)
error("Fehler beim binden des Sockets");
This normally results from an attempt to bind to an address that is not valid for the local computer..
You should use PF_INET here instead of AF_INET. They have the same value, but you're not specifying an address family AF here, you're specifying a protocol family PF. This is just a style recommendation.
I would suggest to memset zero the below arrays,structures:
struct sockaddr_in6 server, client;
SOCKET sock;
char buffer[BUFFERSIZE];
LPTSTR recvBuff[1024];
Before you can use the sockaddr_in6 struct, you will have to memset it to zero:
memset(server, 0, sizeof(struct sockaddr_in6));
The reason is that the struct sockaddr_in6 structure contains other fields which you are not initializing (such as sin6_scope_id) and which might contain garbage.
I have faced the same error.
#askMish 's answer is quite right.I didn't understand it at the first place,however I find it out eventually.
This normally results from an attempt to bind to an address that is not valid for the local computer..
Normally we have our computer under some gateway.
If we run ipconfig we will find the IP address is 192.168.something.
So that's the IP we could use to bind in code.
While other should connect with the public IP(if you can surf Internet you have one for sure.) like 47.93.something if they are in the same LAN with you.
You need to find that IP at your gateway(possibly your family's route).
I had that same error code when calling bind() under windows.
The reason in my case was not the same as in the initial poster's code, but i guess other will have made the very same mistake as me:
I generated the local address on which i want the server to be bound locally using the inet_addr()-function.
I assigned this result to the local address structure struct sockaddr_in localaddr this way:
localaddr.sin_addr.s_addr = htonl(inaddr);
But inet_addr() already returns the address in byte-network-order, so the call htonl(inaddr) was wrong in my code and caused error 10049:
SOCKET tcpsock_bindlisten(unsigned short port, const char* bindaddr)
{
SOCKET srvsock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
unsigned long inaddr = bindaddr ? inet_addr(bindaddr) : INADDR_ANY;
struct sockaddr_in localaddr;
memset(&localaddr, 0, sizeof(struct sockaddr_in));
localaddr.sin_family = AF_INET;
localaddr.sin_port = htons(port);
// ERROR HERE! address returned from inet_addr is already in network-byte-order!
localaddr.sin_addr.s_addr = htonl(inaddr);
// CORRECT THIS WAY:
localaddr.sin_addr.s_addr = inaddr;
if (bind(srvsock, (struct sockaddr *) &localaddr, sizeof(localaddr)) != 0)
{
print_socketerror("tcpsock bind()");
return INVALID_SOCKET;
}
if (listen(srvsock, SVRSOCK_BACKLOG) != 0)
{
print_socketerror("tcpsock listen()");
return INVALID_SOCKET;
}
return srvsock;
}
When calling bind() using "all local interfaces" (INADDR_ANY) it worked, because of this coincidence INADDR_ANY == htonl(INADDR_ANY):
int main()
{
...
// this works for this special case:
SOCKET svrsock1 = tcpsock_bindlisten(4444, NULL);
// did not work!
SOCKET svrsock2 = tcpsock_bindlisten(5555, "192.168.0.123");
}

Extract IP from connection that listen and accept in socket programming in Linux in c

In the following code I would like to extract the IP address of the connected client after accepting an incoming connection. What should I do after the accept() to achieve it?
int sockfd, newsockfd, portno, clilen;
portno = 8090;
clilen = 0;
pthread_t serverIn;
struct sockaddr_in serv_addr, cli_addr;
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
{
perror("ERROR opening socket");
}
bzero((char *) & serv_addr, sizeof (serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(portno);
serv_addr.sin_addr.s_addr = INADDR_ANY;
if (bind(sockfd, (struct sockaddr *) & serv_addr, sizeof (serv_addr)) < 0)
{
perror("ERROR on binding");
}
listen(sockfd, 5);
clilen = sizeof (cli_addr);
newsockfd = accept(sockfd, (struct sockaddr *) & cli_addr, &clilen);
Your cli_addr already contains the IP address and port of the connected client after accept() returns successfully, in the same format as your serv_addr variable. Use inet_ntop to convert IP to a string.
getpeername()
See the helpful description of how to use it over at the indispensable Beej's Guide to Network Programming.
You can follow this example :
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
{
int s;
struct sockaddr_in peer;
int peer_len;
.
.
.
/* We must put the length in a variable. */
peer_len = sizeof(peer);
/* Ask getpeername to fill in peer's socket address. */
if (getpeername(s, &peer, &peer_len) == -1) {
perror("getpeername() failed");
return -1;
}
/* Print it. The IP address is often zero because */
/* sockets are seldom bound to a specific local */
/* interface. */
printf("Peer's IP address is: %s\n", inet_ntoa(peer.sin_addr));
printf("Peer's port is: %d\n", (int) ntohs(peer.sin_port));
.
.
.
}
I think getpeername() is not needed - the client address is already filled into cli_addr by the accept() call.
You only need to use inet_ntop(), getnameinfo(), or gethostbyaddr() to print or get more information.
The API is described in the manual pages. You can either browse them from the console, starting with man socket and follow references to man getpeername or use Konqueror, which renders it nicely with links, if you ask for #socket address. In my case on Kubuntu it was necessary to install manpages-dev package.

Resources