I've written a simple echo server, which includes the following line:
int yes = 1;
if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
However despite this, I'm still getting an error when I try to call bind on a socket I've recently used. In fact, I'm getting this error if I try to call bind on a socket I've used in this program, period, even if it's not recent - like they're not being cleared by the kernel or something. Is there something else I have to do?
Here's the full code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <unistd.h>
void prepareHints(struct addrinfo *hints, int tcp_udp) {
memset(hints, 0, sizeof(struct addrinfo));
hints->ai_family = AF_UNSPEC;
hints->ai_socktype = (tcp_udp == 1) ? SOCK_STREAM : SOCK_DGRAM;
hints->ai_flags = AI_PASSIVE; /* autofill IP */
}
void writeSocket(int fd, const char *msg) {
size_t nbytes = 0;
size_t len = strlen(msg);
while (nbytes < len)
nbytes += send(fd, msg, len, 0);
}
void waitLoop(int sockfd) {
int clientfd, nbytes;
struct sockaddr addr;
socklen_t len;
char buf[512];
while(1) {
clientfd = accept(sockfd, &addr, &len);
if (clientfd < 0) {
perror("accept");
exit(1);
}
while ((nbytes = recv(clientfd, buf, 512, 0)) != EOF) {
buf[nbytes] = '\0';
strcat(buf, "\r\n");
writeSocket(clientfd, buf);
}
close(clientfd);
}
}
int main(int argc, char **argv) {
const char *port = (argc >= 2) ? argv[1] : "7474";
struct addrinfo hints, *res;
prepareHints(&hints, 1);
int status = getaddrinfo(NULL, port, &hints, &res);
if (status != 0) {
printf("Error on getaddrinfo\n");
exit(1);
}
/* scan through sockaddr's returned by getaddrinfo until we successfully set up a socket with one */
int socketfd;
struct addrinfo *cur;
for (cur = res; cur != NULL; cur = cur->ai_next) {
if ((socketfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) >= 0)
break;
}
/* make sure we actually found one */
if (socketfd == -1) {
printf("Error on socket\n");
exit(1);
}
/* bind the socket to the struct sockaddr_in contained in res */
int bindres = bind(socketfd, cur->ai_addr, cur->ai_addrlen);
if (bindres != 0) {
perror("bind");
exit(1);
}
int yes = 1;
if (setsockopt(socketfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (listen(socketfd, 5) < 0) {
printf("error on listen\n");
exit(1);
}
printf("success, listening on socket %d, port %d\n", socketfd, ntohs(((struct sockaddr_in *)res->ai_addr)->sin_port));
waitLoop(socketfd);
return 0;
}
You are setting SO_REUSEADDR after calling bind(). You need to set it before binding, not after.
You are getting an error on bind() and you are setting SO_REUSEADDR afterwards. It therefore has no effect.
The short version is that the kernel keeps it around because there's a period of time in which it can't tell if the packets it is getting are for the old program or the new program. It's always safest to wait. That said, my understanding is with modern networks, the chances of old packets coming in a minute late is very small.
The really short version is that it's a feature (at least it used to be) not a bug.
Related
I'm currently learning network programming in university and programmed a server. As we need this one for further progress I need to reuse the code every time. There is a random function with an error I don't really get because on the linux pcs at university everything compiles well only my mac which I do all my homework shows this error.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <time.h>
//#define PORT "3490" // the port users will be connecting to
#define BACKLOG 10 // how many pending connections queue will hold
int random(int min, int max){
srand ( time(NULL) );
return min + rand() / (RAND_MAX / (max - min + 1) + 1);
}
void sigchld_handler(int s)
{
// waitpid() might overwrite errno, so we save and restore it:
int saved_errno = errno;
while(waitpid(-1, NULL, WNOHANG) > 0);
errno = saved_errno;
}
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[])
{
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
struct addrinfo hints, *servinfo, *p;
struct sockaddr_storage their_addr; // connector's address information
socklen_t sin_size;
struct sigaction sa;
int yes=1;
char s[INET6_ADDRSTRLEN];
int rv;
//int linetoread;
if (argc != 3) {
fprintf(stderr,"usage: server port txtfile\n");
exit(1);
}
FILE* fp;
char buffer[255];
int i = 0;
char rnd[200][255];
int fixed;
fp = fopen(argv[2], "r");
while(fgets(buffer, 255, (FILE*) fp)) {
//printf("%s\n", buffer);
for (int j = 0; j < 255; j++){
rnd[i][j] = buffer[j];
}
i++;
}
fclose(fp);
//printf("number of lines: %d\n", i);
//linetoread = rand() % i;
//printf("%d\n", random(0,i));
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE; // use my IP
if ((rv = getaddrinfo(NULL, argv[1], &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
sizeof(int)) == -1) {
perror("setsockopt");
exit(1);
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("server: bind");
continue;
}
break;
}
freeaddrinfo(servinfo); // all done with this structure
if (p == NULL) {
fprintf(stderr, "server: failed to bind\n");
exit(1);
}
if (listen(sockfd, BACKLOG) == -1) {
perror("listen");
exit(1);
}
sa.sa_handler = sigchld_handler; // reap all dead processes
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART;
if (sigaction(SIGCHLD, &sa, NULL) == -1) {
perror("sigaction");
exit(1);
}
printf("server: waiting for connections...\n");
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
fixed = random(0,i-1);
//printf("line: %d\n", fixed);
if (send(new_fd, rnd[fixed], strlen(rnd[fixed]), 0) == -1)
perror("send");
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
return 0;
}
Error on my mac:
server.c:16:5: error: conflicting types for 'random'
int random(int min, int max){
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/stdlib.h:233:7: note:
previous declaration is here
long random(void) __swift_unavailable("Use arc4random instead.");
^
server.c:132:19: error: too many arguments to function call, expected 0, have 2
fixed = random(0,i-1);
~~~~~~ ^~~~~
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/stdlib.h:233:1: note:
'random' declared here
long random(void) __swift_unavailable("Use arc4random instead.");
^
2 errors generated.
random() is a known function name. change it to something else and it will work.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I'm trying to communicate through a connected-udp-socket between two peer's. The address information between the peers is transmitted via a server using tcp.
First each peer set's up an udp-socket, binds an address and then transmit the address information via tcp to a server. The server sends the connection information to the other peer.
When the peer receives the information it tries to 'connect' the udp-socket to the other peer. The connect call succeed, but send gives me the following error: 'errno: 89, Destination address required'.
peer.c:
#include "Socket.h"
#include "function.h"
int main (int argc, char** argv) {
if(argc != 4) {
printf("3 Parameter must be given.\nclient-ip server-ip server-port\n");
exit(-1);
}
struct sockaddr_in my_addr, server_addr, other_peer_addr;
address_info* msg_address_info;
header *msg;
int recv_done = 0;
int optval = 1;
int fd_udp, fd_server;
ssize_t len;
socklen_t my_addr_len;
fd_set rfds;
FD_ZERO(&rfds);
fd_udp = Socket(AF_INET, SOCK_DGRAM, 0);
memset((void *) &my_addr, 0, sizeof(my_addr));
my_addr.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
my_addr.sin_len = sizeof(struct sockaddr_in);
#endif
my_addr.sin_port = 0; // any port
if ((my_addr.sin_addr.s_addr = (in_addr_t)inet_addr(argv[1])) == INADDR_NONE) {
fprintf(stderr, "Invalid address\n");
}
Bind(fd_udp, (const struct sockaddr *) &my_addr, sizeof(my_addr));
Setsockopt(fd_udp, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int));
Setsockopt(fd_udp, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(int));
memset((void *) &my_addr, 0, sizeof(my_addr));
my_addr_len = sizeof(my_addr);
//get the current address for server registration
Getsockname(fd_udp, (struct sockaddr *) &my_addr, &my_addr_len);
/* TCP Communication */
/* i use 127.0.0.1:55555 for the server */
fd_server = Socket(AF_INET, SOCK_STREAM, 0);
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
#ifdef HAVE_SIN_LEN
server_addr.sin_len = sizeof(struct sockaddr_in);
#endif
server_addr.sin_port = htons(atoi(argv[3]));
if ((server_addr.sin_addr.s_addr = (in_addr_t) inet_addr(argv[2]))
== INADDR_NONE) {
fprintf(stderr, "Invalid address\n");
}
Connect(fd_server, (const struct sockaddr *) &server_addr, sizeof(server_addr));
len = sizeof(address_info);
msg_address_info = malloc(len + get_padding(len));
memset((void*)msg_address_info, 0, len + get_padding(len));
msg_address_info->head.type = htons(30);
msg_address_info->head.length = htons(sizeof(address_info));
msg_address_info->ip = my_addr.sin_addr.s_addr;
msg_address_info->port = my_addr.sin_port;
Send(fd_server, msg_address_info, len + get_padding(len), 0);
free(msg_address_info);
while(!recv_done) {
FD_ZERO(&rfds);
FD_SET(fd_server, &rfds);
//data is ready for recv
if(FD_ISSET(fd_server, &rfds)) {
msg = recv_stream(fd_server);
if(msg != NULL) {
if(ntohs(msg->type) == 3) {
Close(fd_server);
recv_done = 1;
msg_address_info = (address_info *) msg;
other_peer_addr.sin_addr.s_addr = msg_address_info->ip;
other_peer_addr.sin_port = msg_address_info->port;
}
}
}
}
char buf[512];
memset((void*)&buf, 0, 512);
char* other_peer_ip;
int other_peer_port;
other_peer_ip = inet_ntoa(other_peer_addr.sin_addr);
other_peer_port = ntohs(other_peer_addr.sin_port);
printf("other_peer ip: %s\nother_peer port: %i\n", other_peer_ip, other_peer_port); //matches on bothe peer's
int ret_con = connect(fd_udp, (const struct sockaddr *) &other_peer_addr, sizeof(other_peer_addr));
fprintf(stderr, "ret_con: %i, errno: %i, %s\n", ret_con, errno, strerror(errno));
int ret_send = send(fd_udp, buf, 512, 0);
if(ret_send < 0) {
fprintf(stderr, "ret_send: %i, errno: %i, %s\n", ret_send, errno, strerror(errno));
}
}
function.h:
#define BUFFER_SIZE (1<<16)
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <err.h>
#include <netdb.h>
#include <errno.h>
#include "Socket.h"
typedef struct {
uint16_t type;
uint16_t length;
} header;
typedef struct {
header head;
uint32_t ip;
uint16_t port;
} address_info;
int get_padding(int length);
void* recv_stream(int fd);
functions.c:
#include "functions.h"
void* recv_stream(int fd) {
if(fd < 0) {
fprintf(stderr, "recv_stream: Invaild fd\n");
return NULL;
}
ssize_t len;
int msg_length;
char buf[BUFFER_SIZE];
char* msg;
len = recv(fd, &buf, BUFFER_SIZE, MSG_PEEK);
//Client has closed the connection
if(len <= 0) {
fprintf(stderr, "recv_stream: Client closed the connection.\n");
exit(-1);
}
#ifdef DEBUG
printf("PEEKED %zd bytes.\n", len);
#endif
if(len < sizeof(header)) {
fprintf(stderr, "recv_stream: Message to small no header\n");
return NULL;
}
header *head = (header *) buf;
msg_length = ntohs(head->length);
if(len < msg_length) {
fprintf(stderr, "recv_stream: Message to small\n");
return NULL;
}
else if(len >= msg_length + get_padding(msg_length)) {
msg = malloc(msg_length + get_padding(msg_length));
len = Recv(fd, msg, msg_length + get_padding(msg_length), 0);
head = (header *) msg;
}
return head;
}
int get_padding(int length) {
if(length <= 0) {
fprintf(stderr, "get_padding: wrong length");
}
int pad = length % 4;
if(pad == 3)
pad = 1;
else if(pad == 1)
pad = 3;
return pad;
}
Socket.c with Wrapper functions
int Socket(int fd, int type, int protocol) {
int n;
if((n=socket(fd,type,protocol)) < 0) {
perror("socket");
exit(-1);
}
return n;
}
/* many more */
I read already following question Can you bind() and connect() both ends of a UDP connection but it did not solve my problem.
The transfer of the address information seems to be correct. I printed the send and received addresses on both peers and they match.
I'm stucked on this problem and can't figure out my mistake. Can you help me?
Edit:
provided new example
Now i get the following error:
ret_con: -1, errno: 97, Address family not supported by protocol
ret_send: -1, errno: 89, Destination address required
You are not populating the sin_family field of other_peer_addr before calling connect() on the UDP socket. You are only populating the sin_addr and sin_port fields, which is not enough. connect() needs to be told the type of address being passed to it and that must use the same family as the socket (just like with bind()). Since you are not populating the sin_family field, it contains a random value from the stack, and that is causing connect() to fail with the "Address family not supported" error, and send() cannot be called on an unconnected socket, thus causing the "Destination address required" error.
I am having issues with my UDP server accepting any input since I put in a select statement. The intention is to wait on packets from 2 different sockets (with differing ports). At the same time I also want it to be able to tell when the server wants to send something to one of the ports being synchronously listened to. In the following code the program runs until it gets to the select() statement, at which point if i attempt to send something to the server (on the local machine) nothing is accepted and the program hangs, waiting. I have also tried commenting out the writefds fd_set and its accompanying FD_ISSET but the same thing happens. I'm burnt out trying to figure this stuff out so there are probably a ton of things that don't make sense, but I tried my best in my current state. I appologize.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MYPORT "20444" // the port users will be connecting to
#define MAXBUFLEN 1024 //maximum packet length
#define SERVER_R 142.66.140.13 //Server to the "right" of current
#define RTEX_R_PORT "20445" //Port for routing table exchange
typedef enum {false, true} bool;
/*struct to store packet fields into
seq: sequence number;
type: message type; send get ACK
src: client's unique 10 digit number
dst: destination's unique 10 digit number
payload: the message being transferred, if there is any
*/
struct packet
{
char seq[4];
char type[5];
char src[11];
char dst[11];
char payload[MAXBUFLEN];
};
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
//rr: reading from server to the "right"
//rw: writing to the server to the "right"
int sockfd, rtex_rr_sockfd, rtex_rw_sockfd, rv, rrr, rrw, numbytes, i, j, first, max_fd;
struct addrinfo hints, *servinfo, *p, *p2, *p3;
struct sockaddr_storage their_addr, right_addr;
fd_set readfds, writefds;
char buf[MAXBUFLEN];
char temp_buf[MAXBUFLEN];
char d_to_s[MAXBUFLEN];
char *field;
socklen_t addr_len;
char s[INET6_ADDRSTRLEN];
FILE *m_storage;
struct packet inet_packet;
static const struct packet EmptyPacket;
static int rt[51][4];
bool re_exists=false;
bool rt_empty=true;
struct timeval tv;
memset(&hints, 0, sizeof hints);//"zero out" the hints struct
hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4
hints.ai_socktype = SOCK_DGRAM;
hints.ai_flags = AI_PASSIVE; // use my IP
//prepare socket address structures and store them in servinfo and store in linked list
if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and bind to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("listener: bind");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "listener: failed to bind socket\n");
return 2;
}
if ((rrr = getaddrinfo(NULL, RTEX_R_PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rrr));
return 1;
}
for(p2 = servinfo; p2 != NULL; p2 = p2->ai_next) {
if ((rtex_rr_sockfd = socket(p2->ai_family, p2->ai_socktype,
p2->ai_protocol)) == -1) {
perror("listener: socket");
continue;
}
if (bind(rtex_rr_sockfd, p2->ai_addr, p2->ai_addrlen) == -1) {
close(rtex_rr_sockfd);
perror("listener: bind");
continue;
}
break;
}
if (p2 == NULL) {
fprintf(stderr, "listener: failed to bind socket\n");
return 2;
}
if((rrw = getaddrinfo(NULL, RTEX_R_PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rrw));
return 1;
}
for(p3 = servinfo; p3 != NULL; p3 = p3->ai_next) {
if((rtex_rw_sockfd = socket(p3->ai_family, p3->ai_socktype,
p3->ai_protocol)) == -1) {
perror("server: socket");
continue;
}
break;
}
if (p3 == NULL) {
fprintf(stderr, "listener: failed to bind socket\n");
return 2;
}
//free up memory no longer needed after binding has completed
freeaddrinfo(servinfo);
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_SET(rv, &readfds);
FD_SET(rrr, &readfds);
FD_SET(rrw, &writefds);
printf("Listen Mode\n");
//main while loop, listens for packets.
//Upon receipt of packet, information is stored in a struct for processing.
first=0;
while(1)
{
i=0;
inet_packet = EmptyPacket;
rt_empty=true;
tv.tv_sec = 50;
if(rv > rrr && rv > rrw)
max_fd = (rv + 1);
else if(rrr > rv && rrr > rrw)
max_fd = (rrr + 1);
else if(rrw > rv && rrw > rrr)
max_fd = (rrw + 1);
printf("before select...\n");
select(max_fd, &readfds, &writefds, NULL, NULL);
printf("after select...\n");
addr_len = sizeof their_addr;
if(FD_ISSET(rv, &readfds))
{
printf("rv is set...\n");
if((numbytes = recvfrom(sockfd, buf, sizeof(buf), 0,
(struct sockaddr *)&their_addr, &addr_len)) == -1) {
perror("recvfrom");
exit(1);
}
} else if(FD_ISSET(rrr, &readfds))
{
printf("rr read is set...\n");
if((numbytes = recvfrom(rtex_rr_sockfd, buf, sizeof(buf), 0,
(struct sockaddr *)&right_addr, &addr_len)) == -1) {
perror("recvfrom");
exit(1);
}
} else if(FD_ISSET(rrw, &writefds))
{
printf("rr write is set...\n");
if((numbytes = sendto(rtex_rw_sockfd, inet_packet.payload, sizeof(inet_packet.payload),
0, p3->ai_addr, p3->ai_addrlen)) == -1) {
perror("sendto rr");
exit(1);
}
}
Run your program and press enter at the terminal after it has started. It'll probably return from the select. Why? Because the only thing you told select to listen to is fd 0, stdin! rv, rrr and rrw are all just return values from getaddrinfo() and you're just ignoring the actual fd's returned by socket(). max_fd will also be a junk value since all the tested values are equal with each other. (If it happens to be zero, it won't even react to stdin)
Also, next time, please reduce the code to a minimal example. If your problem is select not returning, then eg. all the handling code is completely irrelevant, one socket would be enough and using getaddrinfo() is extra. Also, you would possibly have found the error yourself when removing the getaddrinfo() stuff for the sake of a minimal example.
I'm trying to make a server and client. But when I try to connect the client to the server, I get connection refused. The other answers on stack overflow said to make sure you have listen() and accept(), which I do, and to check the firewalls. So I turned off all the firewalls just to make sure.
I still get connection refused, so I tried ./telnet 10.1.10.13 9696, and got:
Trying 10.1.10.13...
telnet: connect to address 10.1.10.13: Connection refused
telnet: Unable to connect to remote host
Here's the code for the server
int setUpServer(struct fuzzerObj *ptr)
{
/* Declarations */
int hostSocket, yes = 1, rtrn;
union
{
struct sockaddr_in in;
}address;
/* Create Socket */
hostSocket = socket(AF_INET, SOCK_STREAM, 0);
if(hostSocket < 0)
{
errorHandler("Could not create socket\n", FUNCTION_ID_SET_UP_SERVER);
return -1;
}
/* Reuse Address */
rtrn = setsockopt(hostSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
if(rtrn < 0)
{
errorHandler("Couldn't Reuse Address\n", FUNCTION_ID_SET_UP_SERVER);
return -1;
}
errno = 0;
/* Set Up Struct */
address.in.sin_len = sizeof(address.in);
address.in.sin_family = AF_INET;
address.in.sin_port = BBPORT_NUMBER;
address.in.sin_addr.s_addr = htonl(INADDR_ANY);
memset(address.in.sin_zero, 0, sizeof(address.in.sin_zero));
/* Bind Address to Socket */
rtrn = bind(hostSocket, (struct sockaddr*) &address, address.in.sin_len);
if(rtrn < 0)
{
errorHandler("Can't Bind Address to Socket\n", FUNCTION_ID_SET_UP_SERVER);
perror("");
return -1;
}
/* listen */
rtrn = listen(hostSocket, ptr->numberOfClients);
if(rtrn < 0)
{
errorHandler("Can't Listen\n", FUNCTION_ID_SET_UP_SERVER);
return -1;
}
while(1) acceptClient(hostSocket);
return 0;
}
int acceptClient(int fd)
{
struct sockaddr_storage addr;
socklen_t addr_len = sizeof(addr);
int clientFd = accept(fd, (struct sockaddr *) &addr, &addr_len);
if(clientFd < 0)
{
printf("Can't Accept Client\n");
return -1;
}
return clientFd;
}
and the code for the client:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdbool.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#define BLACKBOX_PORT 9696
int main(int argc, char *argv[])
{
/* Check To See If an argument was passed */
if(argc < 2)
{
printf("No enough Arguments\n");
return -1;
}
/* Declaration's */
const char *ip = argv[1];
int sockfd, fd, rtrn;
char *inBuf;
struct sockaddr_in servaddr,cliaddr;
socklen_t len = sizeof(cliaddr);
/* Get Socket to Connect to Fuzz Server */
sockfd = socket(PF_INET, SOCK_STREAM, 0);
if(sockfd < 0)
{
perror("Can't Create Socket");
return -1;
}
/* Fill Out Struct */
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(BLACKBOX_PORT);
inet_pton(AF_INET, ip, &servaddr.sin_addr);
/* Attempt Connection */
fd = connect(sockfd,(struct sockaddr *)&servaddr, sizeof(servaddr));
if(fd < 0)
{
perror("Can not connect to BlackBox Fuzz server");
return -1;
}
/* Allocate Space in Memory for Incoming Connection */
inBuf = (char *) malloc(1025);
if(inBuf == NULL)
{
perror("Mem Error");
return -1;
}
/* Read From Socket */
rtrn = read(fd, inBuf, 1024);
if(rtrn < 0)
{
perror("Can't Read Data From BlackBox Server");
return -1;
}
printf("Received Data: %s\n", inBuf);
free(inBuf);
return 0;
}
Output from client:
./client 10.1.10.13
Can not connect to BlackBox Fuzz server
Connection refused
Any help would be appreciated, thanks.
Assuming that you're running this code on a little-endian machine, you need to use htons() when assigning the port number on the server side too.
(On big-endian machines htons() is a "no-op", but you should always use it to ensure portability)
my assignment was to build a chat server and client with the beej's guide examples so the client can upload a file to the server.
the instructions were to mmap the file and send the data using send().
iv'e tried first just to send simple txt file but it wont work.
for some reason when debug the program and execcutes it line by line it works.
maybe someone can point out what am i missing?
client code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#define PORT "6667" // the port client will be connecting to
#define MAXDATASIZE 256 // max number of bytes we can get at once
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(int argc, char *argv[])
{
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
int sockfd, numbytes;
char buf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv;
char s[INET6_ADDRSTRLEN];
struct stat mystat;
char* pmap;
int fdin;
if (argc != 2) {
fprintf(stderr,"usage: client hostname\n");
exit(1);
}
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
// loop through all the results and connect to the first we can
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((sockfd = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("client: socket");
continue;
}
if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
perror("client: connect");
continue;
}
break;
}
if (p == NULL) {
fprintf(stderr, "client: failed to connect\n");
return 2;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("client: connecting to %s\n", s);
freeaddrinfo(servinfo); // all done with this structure
FD_SET(sockfd,&master);
FD_SET(0,&master);
for(;;)
{
read_fds = master;
if (select(sockfd+1, &read_fds, NULL, NULL, NULL) == -1)
{
perror("select");
exit(4);
}
if (FD_ISSET(0,&read_fds))
{
//reads messege form user
scanf ("%[^\n]%*c", buf);
//if it is upload
if (0 == strncmp(buf,"/upload ",8)) {
//sendFile(sockfd,buf);
if (send(sockfd,buf ,strlen(buf),0) == -1)
perror("send");
if ((fdin = open(buf + 8,O_RDONLY)) < 0)
perror("open");
fstat (fdin,&mystat);
pmap = mmap (0, mystat.st_size, PROT_READ, MAP_SHARED, fdin, 0);
if (send(sockfd,pmap,(int)mystat.st_size,0))
perror("send");
close(fdin);
}
else if (send(sockfd,buf,strlen(buf),0) == -1)
perror("send");
}
else if (FD_ISSET(sockfd, &read_fds))
{
if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1)
{
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
printf("%s\n",buf);
}
}
close(sockfd);
return 0;
}
server code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <libgen.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>
#define PORT "6667" // port we're listening on
// get sockaddr, IPv4 or IPv6:
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
int main(void)
{
struct User *usersPtr = NULL; //ptr to users list
struct File *filesPtr = NULL; //ptr to files list
fd_set master; // master file descriptor list
fd_set read_fds; // temp file descriptor list for select()
int fdmax; // maximum file descriptor number
int listener; // listening socket descriptor
int newfd; // newly accept()ed socket descriptor
struct sockaddr_storage remoteaddr; // client address
socklen_t addrlen;
char buf[256]; // buffer for client data
char msg[256]; //string to deal with message
int nbytes;
char remoteIP[INET6_ADDRSTRLEN];
int yes=1; // for setsockopt() SO_REUSEADDR, below
int i, j, rv;
struct addrinfo hints, *ai, *p;
char path[100],data[1000];
int fdout;
char* pmap;
int pid;
FD_ZERO(&master); // clear the master and temp sets
FD_ZERO(&read_fds);
// get us a socket and bind it
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if ((rv = getaddrinfo(NULL, PORT, &hints, &ai)) != 0) {
fprintf(stderr, "selectserver: %s\n", gai_strerror(rv));
exit(1);
}
for(p = ai; p != NULL; p = p->ai_next) {
listener = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
if (listener < 0) {
continue;
}
// lose the pesky "address already in use" error message
setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
if (bind(listener, p->ai_addr, p->ai_addrlen) < 0) {
close(listener);
continue;
}
break;
}
// if we got here, it means we didn't get bound
if (p == NULL) {
fprintf(stderr, "selectserver: failed to bind\n");
exit(2);
}
freeaddrinfo(ai); // all done with this
// listen
if (listen(listener, 10) == -1) {
perror("listen");
exit(3);
}
// add the listener to the master set
FD_SET(listener, &master);
// keep track of the biggest file descriptor
fdmax = listener; // so far, it's this one
// main loop
for(;;) {
read_fds = master; // copy it
if (select(fdmax+1, &read_fds, NULL, NULL, NULL) == -1) {
perror("select");
exit(4);
}
// run through the existing connections looking for data to read
for(i = 0; i <= fdmax; i++) {
if (FD_ISSET(i, &read_fds)) { // we got one!!
if (i == listener) {
// handle new connections
addrlen = sizeof remoteaddr;
newfd = accept(listener,(struct sockaddr *)&remoteaddr,&addrlen);
if (newfd == -1) {
perror("accept");
}
else {
FD_SET(newfd, &master); // add to master set
if (newfd > fdmax) { // keep track of the max
fdmax = newfd;
}
printf("selectserver: new connection from %s on "
"socket %d\n",inet_ntop(remoteaddr.ss_family,get_in_addr((struct sockaddr*)&remoteaddr),
remoteIP, INET6_ADDRSTRLEN),newfd);
}
}
else {
// handle data from a client
if ((nbytes = recv(i, buf, sizeof buf, 0)) <= 0) {
// got error or connection closed by client
if (nbytes == 0) {
// connection closed
printf("selectserver: socket %d hung up\n", i);
}
else {
perror("recv");
}
close(i); // bye!
FD_CLR(i, &master); // remove from master set
}
else { // we got some data from a client
buf[nbytes] = '\0';
else if (0 == strncmp(buf,"/upload ",8)) {
sprintf(path,"%s",basename(buf + 8));
if((fdout = open (path, O_RDWR | O_CREAT | O_TRUNC, 0777)) < 0)
perror("open");
if ((nbytes = recv(i,data,sizeof data,0)) == -1)
perror("recive");
data[nbytes] = '\0';
lseek (fdout, nbytes - 1, SEEK_SET);
write (fdout, "", 1);
pmap = mmap (0, nbytes, PROT_READ | PROT_WRITE, MAP_SHARED, fdout, 0);
memcpy (pmap , data, nbytes);
close(fdout);
}
else {
for(j = 0; j <= fdmax; j++) { // send to everyone!
if (FD_ISSET(j, &master)) {
if (j != listener && j != i) {
if (send(j, buf, nbytes, 0) == -1) {
perror("send");
}
}
}
}
}
}
} // END handle data from client
} // END got new incoming connection
} // END looping through file descriptors
} // END for(;;)
return 0;
}
Sockets are streams of data, sending 30 bytes then 100 will not result in the server reading 30 bytes then 100, it could read any amount up to 130 bytes. If your file is short, you will probably get the command and the data in one recv.
To get it working for short files containing text (not the complete solution).
The command must be \0 terminated for strlen to give the right size in the server so in the client change:
if (send(sockfd,buf ,strlen(buf),0) == -1)
to
if (send(sockfd,buf ,strlen(buf)+1,0) == -1)
The server will get the command and data together in buf, so in the server change:
char path[100],data[1000];
to
char path[100], *data;
and use data to point to the data in the buffer by changing:
if ((nbytes = recv(i,data,sizeof data,0)) == -1)
perror("recive");
data[nbytes] = '\0';
to
buf[nbytes] = '\0';
data = buf + strlen(buf) + 1;
nbytes = strlen(data);
The full solution is to loop receiving data and to look for the /upload command in stream. You could still look for the \0 as a delimiter, but you should then send the length of the file and use this to determine the number of bytes to read. This will cope with binary files too.