I have a client-server application in C programming language that uses TCP connection. Consider just the server side.
The main function is the following:
int main(int argc, char* argv[])
{
struct addrinfo *ailist, *aip, hint;
int sockfd, err, n;
memset(&hint, 0, sizeof(hint)); //set to 0 all bytes
hint.ai_flags |= AI_PASSIVE;
hint.ai_socktype = SOCK_STREAM;
hint.ai_addr = NULL;
hint.ai_next = NULL;
if((err = getaddrinfo(NULL, "60185", &hint, &ailist))!=0)
{
printf("Error getaddrinfo %d\n", gai_strerror(err));
syslog(LOG_ERR, "ruptimed: getaddrinfo error %s", gai_strerror(err));
exit(1);
}
for (aip = ailist; aip!=NULL; aip = aip->ai_next)
{
if ((sockfd = initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN))>=0)
{
serveImg(sockfd);
printf("Exiting \n");
exit(0);
}
}
exit(1);
}
init_server is the function creating the socket:
int initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen)
{
int fd, err;
int reuse = 1;
if ((fd = socket(addr->sa_family, type, 0))<0)
{
return (-1);
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int))<0)
{
goto errout;
}
if(bind(fd, addr, alen)<0)
{
goto errout;
}
if (type == SOCK_STREAM || type == SOCK_SEQPACKET)
{
if(listen(fd, qlen)<0)
{
goto errout;
}
}
return fd;
errout:
err = errno;
close (fd);
errno = err;
return(-1);
}
As you can see I have used the SOCK_STREAM socket that is used for TCP connections. The application works.
Now I want to convert the application to use SCTP protocol. For that I tried to use SOCK_SEQPACKET instead of SOCK_STREAM. I tried the program both on OSX and on Ubuntu. On the former the function getaddrinfo returns the error Bad hints while on the latter, the main program exit without starting serving (the condition if ((sockfd = initserver(...))>=0) is never satisfied).
How can I convert my TCP application to a SCTP one?
Related
I'm not able to connect to a TCP server on a computer from a client in another computer on the same local network. I'm Getting an error 10060.
I'm able to connect to the server if the client is launched on the same computer as the server.
Here's some info about the server, then the client
(client running on .30 , server = .50)
TCP info of client
Here we can see that my client is sending a SYN signal to the correct IP/PORT
TCP info of Server
The server seems to be listening to any IP and port. So it sounds like I'm not understanding how to set up setsockopt.
Here's the main() of the server that doesnt work if the client isn't on the same computer:
int main(int argc, char **argv){
if(argc != 2){
printf("Usage: %s <port>\n", argv[0]);
return EXIT_FAILURE;
}
// Start of experiment
WORD wVersionRequested;
WSADATA wsaData;
int err;
/* Use the MAKEWORD(lowbyte, highbyte) macro declared in Windef.h */
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (err != 0) {
/* Tell the user that we could not find a usable */
/* Winsock DLL. */
printf("WSAStartup failed with error: %d\n", err);
return 1;
}
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
{
/* Tell the user that we could not find a usable */
/* WinSock DLL. */
printf("Could not find a usable version of Winsock.dll\n");
WSACleanup();
return 1;
}
else
{
printf("The Winsock 2.2 dll was found okay\n");
}
char *ip = "127.0.0.1";
int port = atoi(argv[1]);
//int option = 1;
bool option = TRUE;
int listenfd = 0, connfd = 0;
struct sockaddr_in serv_addr;
struct sockaddr_in cli_addr;
pthread_t tid;
/* Socket settings */
listenfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
serv_addr.sin_port = htons(port);
/* Ignore pipe signals */
//signal(SIGPIPE, SIG_IGN); Sigpipe doesnt exist in NT. I need to implement something ...
if(setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (char *) &option, sizeof(option)) < 0){
perror("ERROR: setsockopt failed\n");
printf("Error : %i\n",WSAGetLastError());
printf("port was: %i\n",port);
printf("Ip Was : %lu\n",serv_addr.sin_addr.s_addr);
WSACleanup();
return EXIT_FAILURE;
}
/* Bind */
if(bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
perror("ERROR: Socket binding failed");
WSACleanup();
return EXIT_FAILURE;
}
/* Listen */
if (listen(listenfd, 10) < 0) {
perror("ERROR: Socket listening failed");
WSACleanup();
return EXIT_FAILURE;
}
printf("=== WELCOME TO THE CHATROOM ===\n");
while(1){
socklen_t clilen = sizeof(cli_addr);
connfd = accept(listenfd, (struct sockaddr*)&cli_addr, &clilen);
/* Check if max clients is reached */
if((cli_count + 1) == MAX_CLIENTS){
printf("Max clients reached. Rejected: ");
print_client_addr(cli_addr);
printf(":%d\n", cli_addr.sin_port);
close(connfd);
continue;
}
/* Client settings */
client_t *cli = (client_t *)malloc(sizeof(client_t));
cli->address = cli_addr;
cli->sockfd = connfd;
cli->uid = uid++;
/* Add client to the queue and fork thread */
queue_add(cli);
pthread_create(&tid, NULL, &handle_client, (void*)cli);
/* Reduce CPU usage */
sleep(1);
}
WSACleanup();
return EXIT_SUCCESS;
}
I somehow managed to make it work when messing around parameters, but I'm not able to reproduce it since I don't understand how winsock works yet.
I tried to disable Firewall on both computers, but it didn't help.
Thanks a lot for your help !
I'm checking an open source code of a messenger which is not supported anymore.(gtmess .97)(it uses sys/socket.h for it's socket programming).
Unfortunately encountered gethostbyname() function and it returns null for the address which is given as hostname(messenger.hotmail.com), i tried to change code using getaddrinfo() but even getaddrinfo() says there isn't such server.
the question is, is there a way to fix it?(also please consider I'm beginner in socket programming)
here is the code:(commented part is what was written in the source code and uncommented part is mine part which tried to simulate using another method):
/* connect a client socket to a server and return a socket descriptor */
int ConnectToServer(char *addr, int defport)
{
/*
int sfd;
struct sockaddr_in servaddr;
struct hostent *host;
char hostname[256];
int port;
int err;
ParseAddr(hostname, &port, defport, addr);
if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
return -1;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(port);
host = gethostbyname(hostname);
if (host == NULL) {
err = errno;
close(sfd);
errno = err;
return -2;
}
servaddr.sin_addr.s_addr = *((int *) host->h_addr_list[0]);
if (connect(sfd, (struct sockaddr *) &servaddr, sizeof(servaddr))) {
err = errno;
close(sfd);
errno =err;
return -3;
}
return sfd;
*/
struct addrinfo hints, *res , *p;
int sockfd;
int err;
memset(&hints,0,sizeof hints);
hints.ai_family=AF_UNSPEC;
hints.ai_socktype=SOCK_STREAM;
getaddrinfo("messenger.hotmail.com","1863",&hints,&res);
if((sockfd=socket(res->ai_family,res->ai_socktype,res->ai_protocol))<0)
return -1;
if(connect(sockfd,res->ai_addr,res->ai_addrlen)){
err = errno;
close(sockfd);
errno =err;
return -3;
}
return sockfd;
}
edit:
I changed server and loop over to connect but it seems new server has problem too which give connection reset by peer in send() part
/* connect a client socket to a server and return a socket descriptor */
int ConnectToServer(char *addr, int defport)
{
struct addrinfo hints, *res , *p;
int sockfd;
int err;
int rv;
memset(&hints,0,sizeof hints);
hints.ai_family=AF_UNSPEC;
hints.ai_socktype=SOCK_STREAM;
if(rv=getaddrinfo("messenger.hotmail.geo.msnmessenger.msn.com.akadns.net","1863",&hints,&res)!=0){
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
};
for(p=res;p!=NULL;p=p->ai_next){
if((sockfd=socket(p->ai_family,p->ai_socktype,p->ai_protocol))<0){
continue;
}
if(connect(sockfd,p->ai_addr,p->ai_addrlen)){
err = errno;
close(sockfd);
errno =err;
continue;
}
break;
}
if(p==NULL)
return -3;
return sockfd;
}
The hostname messenger.hotmail.com is no longer valid.
It does have a CNAME record for messenger.hotmail.geo.msnmessenger.msn.com.akadns.net, however there is no IP address associated with it. So you won't get any valid addresses back.
All is doing fine here, except that the client can't receive the message, or the server can't send it, I don't know.
I have really little time, so I can't waste it anymore trying to handle this problem, so I turn to you guys. Just one thing that I think (maybe) you have to know: the server is under my network, the client is under my school network.
P.S. the different IPs for the server is because I'm behind a NAT, no problem with that.
Client code
const char* IPSERVER = "87.21.70.136";
int main(int argc, char *argv[]){
struct addrinfo hints, *serverInfo;
int s;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // AF_INET or AF_INET6 to force version
hints.ai_socktype = SOCK_STREAM;
if(getaddrinfo(IPSERVER, "50", &hints, &serverInfo) != 0){
printf("Errore getaddrinfo(). Chiusura...\n");
exit(-1);
}
s = socket(serverInfo->ai_family, serverInfo->ai_socktype, serverInfo->ai_protocol);
printf("Porta: %d\n", ((struct sockaddr_in * ) serverInfo->ai_addr)->sin_port);
if(connect(s, serverInfo->ai_addr, serverInfo->ai_addrlen) < 0)
perror("Errore connect()");
char buf[2000];
int bytes_rec;
if((bytes_rec = recv(s, buf, sizeof buf, 0)) < 0)
perror("Errore recv");
printf("%s\n",buf);
close(s);
return 0;
}
Server code
struct sockaddr_storage clientAddr;
socklen_t addrSize;
struct addrinfo hints, *myInfo;
int s, newS;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever
hints.ai_socktype = SOCK_STREAM;
if(getaddrinfo("192.168.1.2", "50", &hints, &myInfo) < 0)
perror("Errore getaddrinfo()");
printf("Porta: %d\n", ((struct sockaddr_in *) myInfo->ai_addr) -> sin_port);
s = socket(myInfo->ai_family, myInfo->ai_socktype, myInfo->ai_protocol);
if(s < 0)
perror("Errore socket()");
printf("Socket stabilita.\n");
if(bind(s, myInfo->ai_addr, myInfo->ai_addrlen) < 0)
perror("Errore bind()");
printf("Porta creata.\n");
if(listen(s, 5) < 0)
perror("Errore listen()");
printf("Server in ascolto...\n");
addrSize = sizeof clientAddr;
if((newS = accept(s, (struct sockaddr * )&clientAddr, &addrSize) < 0))
perror("Errore accept()");
printf("Invio messaggio in corso...\n");
char *msg = "ciao, mi vedi?";
int len, bytes_sent;
len = strlen(msg);
if((bytes_sent = send(newS, msg, len, 0)) < 0)
perror("Errore send()");
printf("Messaggio inviato.\n");
closesocket(newS);
closesocket(s);
WSACleanup();
return 0;
}
Client output
Porta: 12800
Errore recv: Connection reset by peer
Server output
Porta: 12800
Socket stabilita.
Porta creata.
Server in ascolto...
Invio messaggio in corso...
Errore send(): No error
Messaggio inviato.
Process returned 0 (0x0) execution time : 4.789 s
Press any key to continue.
The server code is clearly using the WinSock API, which means the server is running on Windows.
Socket handles on Windows are unsigned values, so int is the wrong data type to use for them. You need to use the SOCKET type instead. And compare the return value of socket() and accept() again the INVALID_SOCKET constant.
Ignoring socket creation errors and passing invalid sockets to send() and recv() can cause them to fail.
perror() operates on errno, which WinSock (and the Win32 API in general) does not use. That would explain the "no error" message after send() fails, because errno is 0. You have to use WSAGetLastError() instead to get a WinSock error code when a WinSock function fails.
With that said, try this server code:
void psocketerror(const char *msg, int err)
{
fprintf(stderr, "%s: %d\n", msg, err);
}
void psocketerror(const char *msg)
{
psocketerror(msg, WSAgetLastError());
}
int main(int argc, char *argv[])
{
struct sockaddr_storage clientAddr;
socklen_t addrSize;
struct addrinfo hints, *myInfo;
SOCKET s, newS;
int err;
WSADATA wsa;
err = WSAStartup(MAKEWORD(2, 0), &wsa);
if (err != 0) {
psocketerror("Errore WSAStartup()", err);
return 1;
}
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
if ((err = getaddrinfo("192.168.1.2", "50", &hints, &myInfo)) < 0) {
psocketerror("Errore getaddrinfo()", err);
WSACleanup();
return 1;
}
printf("Porta: %d\n", ntohs(((struct sockaddr_in *)(myInfo->ai_addr))->sin_port));
s = socket(myInfo->ai_family, myInfo->ai_socktype, myInfo->ai_protocol);
if (s == INVALID_SOCKET) {
psocketerror("Errore socket()");
WSACleanup();
return 1;
}
printf("Socket stabilita.\n");
if (bind(s, myInfo->ai_addr, myInfo->ai_addrlen) < 0) {
psocketerror("Errore bind()");
closesocket(s);
WSACleanup();
return 1;
}
printf("Porta creata.\n");
if (listen(s, 5) < 0) {
psocketerror("Errore listen()");
closesocket(s);
WSACleanup();
return 1;
}
printf("Server in ascolto...\n");
addrSize = sizeof clientAddr;
newS = accept(s, (struct sockaddr * )&clientAddr, &addrSize)
if (newS === INVALID_SOCKET) {
psocketerror("Errore accept()");
closesocket(s);
WSACleanup();
return 1;
}
printf("Invio messaggio in corso...\n");
char *msg = "ciao, mi vedi?";
int len, bytes_sent;
len = strlen(msg);
if ((bytes_sent = send(newS, msg, len, 0)) < 0) {
psocketerror("Errore send()");
closesocket(newS);
closesocket(s);
WSACleanup();
return 1;
}
printf("Messaggio inviato.\n");
closesocket(newS);
closesocket(s);
WSACleanup();
return 0;
}
Trying to create a server-client application, and I'm having quite a bit of trouble setting up the connection on the server-side. After setting up the socket, and bind()ing the socket, my listen()-call fails with the error message
listen: Invalid argument
which I get from perror()-ing the case where listen() returns -1.
The synopsis of the program is the following: I use getaddrinfo() to generate a linked list of struct addrinfo's, loop through that until I find one that I can successfully create a socket with, then bind() and finally listen().
The listen() call goes as follows:
if ((status = listen(socket_fd, BACKLOG_SIZE)) == -1) {
perror("listen");
close(socket_fd);
freeaddrinfo(res);
exit(EXIT_FAILURE);
}
To be sure, I've printed the values of socket_fd and BACKLOG_SIZE, turning out to be 3 and 5, respectively. Have been debugging for hours now, and I simply cannot find out where the problem lies. Haven't found anyone with the same issue on stackOverflow, either...
Thank you in advance for any help!
Full program:
int main(int argc, char* argv[]) {
int port_no = server_usage(argc, argv);
ready_connection(port_no);
/* Synopsis:
getaddrinfo()
socket()
bind()
listen()
accept()
*/
int socket_fd = setup_socket(NULL, port_no);
struct sockaddr_storage their_addr;
socklen_t addr_size = sizeof(their_addr);
int new_fd = 0;
// Allow reuse of sockets
int activate=1;
setsockopt(socket_fd, IPPROTO_TCP, TCP_NODELAY, &activate, sizeof(int));
if ((status = bind(socket_fd, res->ai_addr, res->ai_addrlen)) == -1) {
perror("bind");
exit(EXIT_FAILURE);
}
if ((status = connect(socket_fd, res->ai_addr, res->ai_addrlen)) == -1) {
perror("connect");
close(socket_fd);
freeaddrinfo(res); // free the linked-list
exit(EXIT_FAILURE);
}
if ((status = listen(socket_fd, BACKLOG_SIZE)) == -1) {
perror("listen");
close(socket_fd);
freeaddrinfo(res); // free the linked-list
exit(EXIT_FAILURE);
}
if ((new_fd == accept(socket_fd, (struct sockaddr *)&their_addr, &addr_size)) == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
char buffer[BUFSIZE];
recv(new_fd, buffer, BUFSIZE, 0);
close(socket_fd);
close(new_fd);
freeaddrinfo(res); // free the linked-list
return 0;
}
setup_socket()-function:
int setup_socket(char* hostname, int port_no) {
// hints is mask struct, p is loop variable
struct addrinfo hints, *p;
memset(&hints, 0, sizeof hints); // make sure the struct is empty
// TODO IPv6-support?
hints.ai_family = AF_INET; // only IPv4 supported
hints.ai_socktype = SOCK_STREAM; // TCP stream sockets
hints.ai_flags = AI_PASSIVE; // fill in my IP for me
char port_str[6]; // max port size is 5 digits + 0-byte
memset(port_str, 0, 6);
sprintf(port_str, "%d", port_no);
if ((status = getaddrinfo(hostname, port_str, &hints, &res)) == -1) {
fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
exit(EXIT_FAILURE);
}
int socket_fd = 0;
for (p = res; p != NULL; p = p->ai_next) {
if ((socket_fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
perror("socket");
exit(EXIT_FAILURE);
}
}
if (socket_fd == 0) {
errno = ENOTSOCK;
perror("no socket");
exit(EXIT_FAILURE);
}
return socket_fd;
}
You cannot connect(), then listen() on the same socket. Lose the connect().
I was trying to do a simple tcp server client using ipv6. It works on the same machine for ipv6 and ipv4 but when on different machines ipv6 fails to connect.
Server Code
int main(int argc, char* argv[])
{
int sockfd,new_fd,rv,yes=1;
struct addrinfo hints,*servinfo,*p;
struct sockaddr_storage their_addr;
socklen_t addr_size;
SOCKET listenSocket,clientSocket;
WSADATA w;
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
exit(0);
}
//ip=argv[1];
//port=argv[2];
memset(&hints,0,sizeof(hints));
hints.ai_family=AF_INET6;
hints.ai_socktype=SOCK_STREAM;
hints.ai_flags=AI_NUMERICHOST;
if((rv = getaddrinfo("fe80::c0a8:0160","5002",&hints,&servinfo)) != 0)
{
perror("\nGetaddrinfo failed\n");
return 1;
}
//Creating socket
listenSocket = socket(servinfo->ai_family,servinfo->ai_socktype,servinfo->ai_protocol);
if(listenSocket == INVALID_SOCKET)
{
printf("\nSocket failed with error \n");
WSACleanup();
}
//setting non blocking mode
u_long iMode = 1;
rv = ioctlsocket(listenSocket,FIONBIO,&iMode);
if(rv == SOCKET_ERROR)
{
printf("\nioctl failed\n");
WSACleanup();
}
rv = bind(listenSocket,servinfo->ai_addr,(int)servinfo->ai_addrlen);
if(rv == SOCKET_ERROR)
{
perror("\nBind: \n");
}
freeaddrinfo(servinfo);
rv = listen(listenSocket,SOMAXCONN);
if(rv == SOCKET_ERROR)
{
perror("listen");
return 1;
}
// now accept an incoming connection:
char recvbuf[DEFAULT_BUFLEN];
int buflen = DEFAULT_BUFLEN;
SOCKET AcceptSocket;
while (1)
{
AcceptSocket = SOCKET_ERROR;
while (AcceptSocket == SOCKET_ERROR)
{
AcceptSocket = accept(listenSocket, NULL, NULL);
}
printf("Server: Client Connected!\n");
listenSocket = AcceptSocket;
rv = recv(listenSocket,recvbuf,buflen,0);
break;
}
printf("Received %d bytes from client \n",rv);
closesocket(listenSocket);
closesocket(AcceptSocket);
return 0;
}
Client Code
int main(int argc,char* argv[])
{
struct addrinfo hints,*servinfo,*p;
int rv;
SOCKET connectSocket;
WSADATA w;
if (WSAStartup(0x0101, &w) != 0)
{
fprintf(stderr, "Could not open Windows connection.\n");
exit(0);
}
//resetting memory
memset(&hints,0,sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICHOST;
//getting values
if((rv = getaddrinfo("fe80::c0a8:160","5002",&hints,&servinfo)) != 0)
{
perror("Getaddrinfo failed");
return 1;
}
//Creating socket
connectSocket = socket(servinfo->ai_family,servinfo->ai_socktype,servinfo->ai_protocol);
if(connectSocket == INVALID_SOCKET)
{
perror("Socket create : ");
}
rv = connect(connectSocket,servinfo->ai_addr,(int)servinfo->ai_addrlen);
if(rv == SOCKET_ERROR)
{
perror("Socket Connect : ");
}
//free memory
freeaddrinfo(servinfo);
// Send and receive data.
int bytesSent;
char sendbuf[200] = "Client: Sending some test string to server...";
char recvbuf[200] = "";
bytesSent = send(connectSocket, sendbuf, strlen(sendbuf), 0);
printf("Client: send() - Bytes Sent: %ld\n", bytesSent);
closesocket(connectSocket);
return 0;
}
The aim is just to print how many bytes transferred.
It appears that you're using a link local address. Are you sure for that? Also, I'd suggest you check your firewall settings first.
EDIT:
Try to include the zone ID. When you issue the ipconfig in command prompt, you should be able to get addresses like fe80::c0a8:0160%21 where %21 is the zone ID. It's important when you use link local addresses according to this answer.