Reputation: 19
I am trying to implement a socket library. It was all doing ok, until I reach accept function. I looked into the stack overflow, and I guy said it won't return until a client is being connected through this but if it is not in blockmode. So, I would like to know: HOW TO CHANGE LISTEN TO NONBLOCK mode?
Here is my header:
#ifndef NET_SOCKET_H
#define NET_SOCKET_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(WIN32) || defined(WINDOWS_XP)
#include <winsock2.h>
#endif
#include <type-of/include/type.h>
#include <unistd.h>
#define NET_SOCK_ALLOCATED 1
typedef struct NetSocket NET_SOCK;
typedef struct sockaddr_in NET_ADDR_IN;
typedef struct sockaddr NET_ADDR;
struct NetSocket {
struct {
B32 sys; // PF_INET or PF_UNIX
B32 data; // SOCK_STREAM or SOCK_DGRAM
B32 mode; // IPPROTO_TCP or IPPROTO_UDP
} from;
#if defined(WIN32) || defined(WINDOWS_XP)
SOCKET sock;
#else
B32 sock;
#endif
B8 * host;
NET_ADDR_IN to;
BIT status;
STATUS(*open)(NET_SOCK * net);
STATUS(*tie)(NET_SOCK * server);
STATUS(*wait)(NET_SOCK * net, B32 max);
STATUS(*join)(NET_SOCK * server, NET_SOCK * client);
STATUS(*in)(NET_SOCK * client);
void (*close)(NET_SOCK * net);
void (*pop)(NET_SOCK * net);
};
NET_SOCK net_sock_std(B8U * host, B32U port);
NET_SOCK * net_sock_push(B8U * host, B32U port);
void net_sock_zero(NET_SOCK * net);
STATUS net_sock_open(NET_SOCK * net);
STATUS net_sock_tie(NET_SOCK * server);
STATUS net_sock_wait(NET_SOCK * net, B32 max);
STATUS net_sock_join(NET_SOCK * server, NET_SOCK * client);
STATUS net_sock_in(NET_SOCK * client);
STATUS net_sock_put(NET_SOCK * net);
void net_sock_close(NET_SOCK * net);
void net_sock_pop(NET_SOCK * net);
void winsock_start();
void winsock_stop();
#ifdef __cplusplus
}
#endif
#endif /* NET_SOCKET_H */
Here is my source:
#include "net_socket.h"
void net_sock_function(NET_SOCK * net){
if(net){
net->open = net_sock_open;
net->tie = net_sock_tie;
net->wait = net_sock_wait;
net->join = net_sock_join;
net->in = net_sock_in;
net->close = net_sock_close;
net->pop = net_sock_pop;
}
}
NET_SOCK net_sock_std(B8U * host, B32U port){
NET_SOCK net;
net_sock_zero(&net);
if(host)net.host = strdup(host);
if(port)net.to.sin_port = htons(port);
bit_off(&net.status,NET_SOCK_ALLOCATED);
return(net);
}
NET_SOCK * net_sock_push(B8U * host, B32U port){
NET_SOCK * net = malloc(sizeof(NET_SOCK));
net_sock_zero(net);
if(host)net->host = strdup(host);
if(port)net->to.sin_port = htons(port);
bit_on(&net->status,NET_SOCK_ALLOCATED);
return(net);
}
void net_sock_zero(NET_SOCK * net){
if(net){
winsock_start();
net->from.data = SOCK_STREAM;
net->from.mode = IPPROTO_TCP;
if(is_win()){
net->from.sys = AF_INET;
net->to.sin_family = AF_INET;
}
else {
net->from.sys = AF_UNIX;
net->to.sin_family = AF_UNIX;
}
net->sock = -1;
net->host = NULL;
net->to.sin_addr.s_addr = htonl(INADDR_ANY);
net->to.sin_port = 0;
net_sock_function(net);
}
}
STATUS net_sock_open(NET_SOCK * net){
if(!net)return(Off);
if( (net->sock = socket(net->from.sys,net->from.data,net->from.mode)) != -1)return(On);
return(Off);
}
STATUS net_sock_tie(NET_SOCK * server){
if(!server)return(Off);
if(bind(server->sock,(NET_ADDR*)&server->to,sizeof(server->to)) != -1)return(On);
return(Off);
}
STATUS net_sock_wait(NET_SOCK * net, B32 max){
if(!net)return(Off);
if(listen(net->sock,max) != -1)return(On);
return(Off);
}
STATUS net_sock_join(NET_SOCK * server,NET_SOCK * client){
if(!server || !client)return(Off);
B32U clientLen = sizeof(client->to);
while((client->sock = accept(server->sock,(NET_ADDR *)&client->to,&clientLen)) == -1)return(On);
return(Off);
}
STATUS net_sock_in(NET_SOCK * client){
if(!client)return(Off);
if(connect(client->sock,(NET_ADDR *)&client->to,sizeof(client->to)) != -1)return(On);
return(Off);
}
STATUS net_sock_put(NET_SOCK * net){
if(!net)return(Off);
return(Off);
}
void net_sock_close(NET_SOCK * net){
if(is_win())closesocket(net->sock);
else close(net->sock);
}
void net_sock_pop(NET_SOCK * net){
if(net){
if(net->host){
free(net->host);
net->host = NULL;
}
if(bit_is_on(net->status,NET_SOCK_ALLOCATED)){
free(net);
net = NULL;
}
}
}
void winsock_start() {
if (is_win()) {
WORD versionWanted = MAKEWORD(1, 1);
WSADATA wsaData;
WSAStartup(versionWanted, &wsaData);
atexit(winsock_stop);
}
}
void winsock_stop() {
if (is_win()) {
WSACleanup();
}
}
And finally my main:
#include "net_socket.h"
void command_line(B32 c, B8 ** v, B8U ** host, B32U * port) {
B32 i = 1;
while (i < c) {
switch (i) {
case 1:
{
*port = atoi(v[i]);
}
break;
case 2:
{
*host = v[i];
}
break;
}
i++;
}
}
int main(int argc, char** argv) {
B8U * host = NULL;
B32U port = 50;
command_line(argc, argv, &host, &port);
NET_SOCK server = net_sock_std(NULL, port);
if (server.open(&server)) {
if (!host) {
NET_SOCK client = net_sock_std("localhost", port);
printf("server openned in %hu\n", server.to.sin_port);
if (client.open(&client)) {
printf("Server client openned in %hu", client.to.sin_port);
}
if (server.tie(&server) && server.wait(&server, 1)){
printf("\nready\n");
}
while (server.join(&server, &client)){ // I can't get in search mode
printf("searching\n");
}
client.pop(&client);
} else {
NET_SOCK client = net_sock_std(host, port);
if (client.open(&client)) {
printf("client openned in %s %hu\n", host, client.to.sin_port);
while (!client.in(&client)) {
printf("trying to connect\n");
}
printf("bye server\n");
}
}
server.close(&server);
}
server.pop(&server);
return (EXIT_SUCCESS);
}
With the help of my friend Jeremy I found: (IT IS JUST TO SET SERVER SOCK TO OFF)
STATUS net_lock_socket(NET_SOCK * net, STATUS block) {
if (!net || net->sock < 0) return Off;
#if defined(WIN32)
unsigned long mode = block ? 0 : 1;
return (ioctlsocket(net->sock, FIONBIO, &mode) == 0) ? On : Off;
#else
int flags = fcntl(net->sock, F_GETFL, 0);
if (flags == -1) return Off;
flags = block ? (flags & ~O_NONBLOCK) : (flags | O_NONBLOCK);
return (fcntl(net->sock, F_SETFL, flags) == 0) ? On : Off;
#endif
}
Upvotes: 0
Views: 76
Reputation: 73061
First, a quick clarification -- it isn't listen()
that will block, but rather accept()
. listen()
simply lets the operating system know that you would like that socket to be able to accept incoming TCP connections in the future; so there is no reason for it to ever block.
Second, to make accept()
non-blocking, you'll need to first make the socket you are calling accept()
on non-blocking -- the info on how to do that is available here.
Once you've done that, instead of not returning until an incoming TCP connection has been detected, accept()
will return -1 and set errno to EWOULDBLOCK
if there is no TCP connection already waiting for it... so in order to know when it's appropriate to call accept()
on the socket, you can include the socket in your read fd-set in your select() call. The accept-socket will signal ready-for-read whenever an incoming TCP connection is present and it's time to call accept() to handle it.
Upvotes: 1