Local socket option set vs pointer to socket option set - c

I wonder... what is the actual difference if you create a function that has a simple socket parameter and you do your basic instructions inside that function like setting different option to that socket (setsockopt()) and after the functions exist it will remain the option? Or should I make that parameter pointer to that socket in order to keep the actual changes that will happen to the socket.
sctp_enable_events( int socket, int ev_mask )
{
struct sctp_event_subscribe ev;
bzero(&ev, sizeof(ev));
if (ev_mask & SCTP_SNDRCV_INFO_EV)
ev.sctp_data_io_event = 1;
/*code */
if (setsockopt(socket,
IPPROTO_SCTP,
SCTP_EVENTS,
SCTP_SET_EVENTS,
(const char*)&ev,
sizeof(ev)) != 0 ) {
fprintf(where,
"sctp_enable_event: could not set sctp events errno %d\n",
errno);
fflush(where);
exit(1);
}
}
Or like this?
sctp_enable_events( int *socket, int ev_mask, struct sctp_event_subscribe *ev )
{
if (ev_mask & SCTP_SNDRCV_INFO_EV)
ev->sctp_data_io_event = 1;
/*code */
if (setsockopt(*socket,
IPPROTO_SCTP,
SCTP_EVENTS,
SCTP_SET_EVENTS,
ev,
sizeof(*ev)) != 0 ) {
fprintf(where,
"sctp_enable_event: could not set sctp events errno %d\n",
errno);
fflush(where);
exit(1);
}
}
I know by passing pointer to struct,int,char etc. you cand modify the values after the function executes and without a pointer the modification will remain local in that function only ,but it will not change it globally.
But how with the setsockopt function?

The setsockopt function can't tell how you come up with it's arguments. Therefore, it cannot act differently. Whether you write:
f(1);
or
int x = 1;
int* xPtr = &x;
f(*xPtr);
is not detectable by f.
This question really has nothing to do with setsockopt. I advise you to strengthen your C knowledge around pointers and values. Without this understanding you are going to make many mistakes in C.

You should generally pass pointers to structs because of the efficiency and because you may want to use those structs (by dereferencing the pointer) in different contexts.
In the case of the socket parameter of the setsockopt(), it is an int, so it is small enough to be passed by value (also the signature of the setsockopt() function requires an int, not a pointer).
As for setsockopt() and other C system API functions, you should lookup its declarations/prototypes and provide the parameters of exactly the same type as the prototype requires (doing the casting if neccessary).
In the case of setsockopt() it would be:
int `setsockopt()` setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);

Related

Why is the first parameter of sctp_inet_listen struct socket* instead of int

I want to study the source code of the kernel network part to understand how the network part of the kernel works.But when I looked at the listen function, I found the above problem. Use man to see that the first parameter of the listen function is int.
int listen(int sockfd, int backlog);
But in https://github.com/torvalds/linux, the first parameter of the sctp_inet_listen function is struct socket*,In protocol.c we know listen is a function pointer of sctp_inet_listen
static const struct proto_ops inet_seqpacket_ops = {
.family = PF_INET,
.owner = THIS_MODULE,
.release = inet_release, /* Needs to be wrapped... */
.bind = inet_bind,
.connect = sctp_inet_connect,
.socketpair = sock_no_socketpair,
.accept = inet_accept,
.getname = inet_getname, /* Semantics are different. */
.poll = sctp_poll,
.ioctl = inet_ioctl,
.gettstamp = sock_gettstamp,
.listen = sctp_inet_listen,
.shutdown = inet_shutdown, /* Looks harmless. */
.setsockopt = sock_common_setsockopt, /* IP_SOL IP_OPTION is a problem */
.getsockopt = sock_common_getsockopt,
.sendmsg = inet_sendmsg,
.recvmsg = inet_recvmsg,
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
};
int sctp_inet_listen(struct socket *sock, int backlog)
{
struct sock *sk = sock->sk;
struct sctp_endpoint *ep = sctp_sk(sk)->ep;
int err = -EINVAL;
if (unlikely(backlog < 0))
return err;
lock_sock(sk);
/* Peeled-off sockets are not allowed to listen(). */
if (sctp_style(sk, UDP_HIGH_BANDWIDTH))
goto out;
if (sock->state != SS_UNCONNECTED)
goto out;
if (!sctp_sstate(sk, LISTENING) && !sctp_sstate(sk, CLOSED))
goto out;
/* If backlog is zero, disable listening. */
if (!backlog) {
if (sctp_sstate(sk, CLOSED))
goto out;
err = 0;
sctp_unhash_endpoint(ep);
sk->sk_state = SCTP_SS_CLOSED;
if (sk->sk_reuse || sctp_sk(sk)->reuse)
sctp_sk(sk)->bind_hash->fastreuse = 1;
goto out;
}
/* If we are already listening, just update the backlog */
if (sctp_sstate(sk, LISTENING))
WRITE_ONCE(sk->sk_max_ack_backlog, backlog);
else {
err = sctp_listen_start(sk, backlog);
if (err)
goto out;
}
err = 0;
out:
release_sock(sk);
return err;
}
In Linux, the C library function listen(fd,backlog) corresponds to a syscall (SYS_listen) with the same prototype. This syscall is implemented in net/socket.c (see SYSCALL_DEFINE2(listen, int, fd, int, backlog)). It calls net/socket.c:__sys_listen().
net/socket.c:__sys_listen() looks up the socket description (which is of type struct socket) by looking up the file description table entry fd, and does basic checks and bookkeeping work.
The struct socket structure contains member ops, which is a pointer to struct proto_ops. This is a set of function pointers, so that different types of sockets (say, Unix domain sockets, or IP sockets) can be supported in the same interface. (Each socket type defines its own proto_ops, basically.)
net/socket.c:__sys_listen() obtains the listen function pointer of that set, and calls it, so that different socket types can implement their own 'listen' facility. Because the file descriptor was already looked up, and converted to a pointer to the socket description, that pointer is passed (instead of the file descriptor). (This same – or very similar – interface is used across all file/socket descriptor using functions.)
The core point to realize here is that file descriptor numbers are just indexes to a process-specific table of references to file descriptions. For sockets, that reference is of type struct sock *. (The table of file descriptions is internal to the kernel, and is usually called file table; the process-specific table of references is usually called file descriptor table; and a file descriptor is an index to the file descriptor table. If you find this confusing, read e.g. the Wikipedia File descriptor article for further details.)

Why do I get "error: too few arguments to function ‘sock->ops->accept’"

I am writing kernel module with sockets. When I try write code for accept connection I get:
"error: too few arguments to function ‘sock->ops->accept’
ret = sock->ops->accept(sock, client_sock, 0);"
I looked into implementation of socket accept and there are only three arguments so I don't know what's going on.
struct socket *sock = NULL, *client_sock = NULL;
//some code here, create socket, bind, listen
ret = sock->ops->accept(sock, client_sock, 0);
I expect that it should works but it doesn't. Why do I get "too few arguments" error if in implementation are only three? How can I fix that?
The prototype of the ->accept() handler was changed between kernel versions 4.10 and 4.11 by this commit: "net: Work around lockdep limitation in sockets that use sockets".
As mentioned in user MofX's answer, the ->accept() handler has a fourth parameter bool kern in current kernel versions (since 4.11). According to the commit description, this is analogous to the kern parameter passed in to ->create(), and distinguishes whether kernel_accept() or sys_accept4() was the caller. See the commit description for details.
If you want your code to work for kernels both before and since 4.11, you will need to use conditional compilation:
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
#define KV_ACCEPT_HAS_BOOL_KERN
#endif
#ifdef KV_ACCEPT_HAS_BOOL_KERN
// your code needs to determine whether 'kern' should be false or true here...
ret = sock->ops->accept(sock, client_sock, 0, kern);
#else
ret = sock->ops->accept(sock, client_sock, 0);
#endif
There are four arguments in proto_ops::accept
struct proto_ops {
...
int (*accept) (struct socket *sock,
struct socket *newsock, int flags, bool kern);
};
See: https://elixir.bootlin.com/linux/latest/source/include/linux/net.h#L147

Pass struct to xv6 system call

I'm aware that we are not able to pass parameters to xv6 system call directly and we are forced to use it's built in methods.
But all examples and questions in this site is about how to send integer to system call. Which it's answer is using argint() method.
But my question is, is there anyway to pass "struct" to a xv6 system call? Are there any bulit-in methods for this purpose too?
If there is, could you please say a simple example?
Passing a struct through system call is possible.
While one can't pass a struct itself as a system call parameter, passing a pointer to it is possible and will allow using it as both an input or output parameter.
Allowing to use as argument the data itself and not a pointer to it will damage the requirement of the system calls mechanism- as passing data must be implemented in a generic way to allow all data types to (as well as future structs) be used.
Let's have a look on an existing implementation of the system call fstat.
int fstat(int fd, struct stat *st);
fstat requires a file descriptor number as an input and outputs a matching stats information using struct stat.
struct stat {
short type; // Type of file
int dev; // File system's disk device
uint ino; // Inode number
short nlink; // Number of links to file
uint size; // Size of file in bytes
};
Although fstat uses a struct pointer as an output parameter, using it as an input will be similar.
The function sys_fstat in kernel code starts the implementation of fstat system call (XV6's convention is to handle parameter fetching from user space by sys_* functions).
int sys_fstat(void)
{
struct file *f;
struct stat *st;
if(argfd(0, 0, &f) < 0 || argptr(1, (void*)&st, sizeof(*st)) < 0)
return -1;
return filestat(f, st);
}
This function first gets a corresponding struct file to the file descriptor number received by the first fstat function argument (using argfd). Then, fetches the struct stat pointer received by the second fstat function argument using argptr and saves the given pointer in a local (function scope) pointer variable.
At this point, all arguments were fetched and can be used by the kernel implementation.
Note: Although the struct stat pointer is a user-space pointer (located on the lower half of the virtual space), it is safe for the kernel to use it here because when the kernel is serving a process' system call, it uses the process' own paging table.
Although the above answer is correct but i prefered to write my own solutions to make it more usable for other viwers.
i used argptr to pass a pointer-to-struct to my system call.
in sysproc.c:
int sys_counts (void){
struct countTable *ct;
argptr (0 , (void*)&ct ,sizeof(*ct));
return counts(ct);
}
in proc.c:
int counts (struct countTable *ct){
for (int i=0 ; i<22 ; i++){
(ct->system_calls)[i] = count_calls[i] ;
}
return 22;
}
and finally in my user-space-program:
int main (){
struct countTable *ct = malloc (sizeof (struct countTable));
// call system call
counts(ct);
exit();
}
Although one of the answers is acceptable I wrote my answer that is clear and complete.
Note that passing an argument to system-call directly is impossible. we will use argptr to do that.
In userspace, we define a struct that we want to work with. in a user-level file like test.c
#include "types.h"
#include "stat.h"
#include "user.h"
struct Data
{
...
int id; // some fields
...
};
int main(int argc, char *argv[])
{
struct Data *data = malloc(sizeof(struct Data));
// call the systemcall
doSomeWork((void *)data);
exit();
}
In sysproc.c we define system-call and use argptr to get arguments:
int sys_doSomeWork(void){
struct Data *data;
argptr(0, (void *)&data, sizeof(*data));
return doSomeWork((void *)data);
}
and in proc.c we can write the functionality of system-call:
int doSomeWork(void *data){
// cast to (struct Data *)
struct Data *my_data = (struct Data *)data;
...
// work with my_data
...
return 0;
}
and to make Data struct accessible inside sysproc.c and proc.c we define Data struct inside defs.h:
struct Data
{
...
int id; // some fields
...
};

Why should the argument of the thread function should be in the heap?

I have written a multi-client server in c, using pthread library. when each client try to connect to the server, each client run as a separate thread and handle each client using handle_client function.
And i want to know why I need to declare connfd as a variable in the heap? What problem might occur if it was declared as a local variable?
This is the code to make each thread (in the main() function)
int* connfd;
pthread_t thread_id;
int client_sock
while (1)
{
connfd = malloc(sizeof(int));
*connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
if( pthread_create( &thread_id , NULL , handle_client , (void*)&client_sock) < 0)
{
perror("could not create thread");
return 1;
}
}
Here is my hadle_client function.
void* handle_client(void* connfd)
{
/* read a string sent by the client,
* print it and then send the string
* "Hello from the server" to the client*/
int sock = *(int*)connfd;
int read_size;
char *message , client_message[2000];
//Send some messages to the client
message = "Hello from the server\n";
write(sock , message , strlen(message));
while( (read_size = recv(sock , client_message , 2000 , 0)) > 0 )
{
//end of string marker
client_message[read_size] = '\0';
//Send the message back to client
puts(client_message);
//clear the message buffer
memset(client_message, 0, 2000);
}
if(read_size == 0)
{
puts("Client disconnected");
fflush(stdout);
}
else if(read_size == -1)
{
perror("recv failed");
}
free(connfd);
return NULL;
}
For the code to work correctly it is necessary to ensure that:
the variable containing the connection handle (in your code, *connfd) exists for as long as it's required by the handle_client thread;
its value doesn't get overwritten by subsequent iterations of the while loop.
It is easier to achieve this with a heap variable, just as you've done in your code.
In general, it is not necessarily wrong to pass the address of a local (automatic, stack-based) variable to a thread function. It just requires a lot more care than using a heap-based variable.
If you use local variable, it will be initialized in main thread's stack. It would be safe to pass the address of that variable to respective threads as main thread's stack variables lifetime will obviously be long enough. But the problem in doing so is you are updating the fd value everytime in while(1) in the same local variable which will make every thread to use that resulting in undefined behavior.
You will have to allocate new variable either in heap or stack for each thread for this reason so that each thread should be able to read correct fd value without any ambiguity.
There are problems
it might be that the lifetime of the variable ends before it is used in the thread. Accessing an object after its lifetime has undefined behaviour
Before C11 no behaviour was specified for accesses to local variables from other threads. As the behaviour is not defined, it is implicitly undefined
C11 says the behaviour of accessing an automatic variable from another thread is implementation-defined:
An object whose identifier is declared with no linkage and without the storage-class specifier static has automatic storage duration, as do some compound literals. The result of attempting to indirectly access an object with automatic storage duration from a thread other than the one with which the object is associated is implementation-defined.
Did you read the compiler manuals yet?
GCC says:
Such accesses are supported, subject to the same requirements for synchronization for concurrent accesses as for concurrent accesses to any object.
Even if the accesses are supported, there is a possibility of data race, including the compiler to decide that the value is not needed any more.
None of these points apply to objects that are dynamically allocated and not modified after the other thread has been started.

Handling errors when refactoring procedural code

I was handed some C code that basically consists of a big main() function. I am now trying to unfold the method into smaller functions, to make clearer the code's intent. I am having some trouble, though:
void main(int argc, char *argv[])
{
if(argc != 3)
{
printf("Usage: table-server <port> <n_lists>\n");
return;
}
int port = atoi(argv[1]), n_lists = atoi(argv[2]);
if(port < 1024 || port > 49151 || n_lists < 1)
{
printf("Invalid args.\n");
return;
}
signal(SIGPIPE, SIG_IGN);
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
struct sockaddr_in s_addr;
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(port);
s_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if(bind(sockfd, (struct sockaddr *)&s_addr, sizeof(s_addr)) < 0)
{
printf("(bind).\n");
return;
}
if(listen(sockfd, SOMAXCONN) < 0)
{
printf("(listen).\n");
return;
}
I can identify 4 main concerns in this code's function:
Verifying the number of args is correct.
Getting from the command line arguments the port.
Calling signal(SIGPIPE, SIG_IGN).
Actually try to make a connection with the socket.
The problem when trying to refactor this into small functions is mainly related with error handling. For instance,r trying to extract the logic of 1. would look like this:
int verify_number_of_args(int argc) {
if (argc != 3) {
printf("...");
return -1;
}
return 0;
}
and calling it would be something like this
if (verify_number_of_args(argc) == -1) return;
which isn't actually that bad. Now, for the socket, that'd be way more troublesome as both sockfd and s_addr need to be returned, plus the status return value:
int sockfd;
struct sockaddr_in* s_addr;
if (create_socket(port, &sockfd, s_addr) == -1)
return;
which kind of defeats the purpose of trying to keep my main method as simple and clear as possible. I could, of course, resort to global variables in the .c file but that doesn't seem that good of an idea.
How do you generally handle this kind of things in C?
Here's the simple approach.
Argument parsing and related error checking are main's concern, so I wouldn't split those out unless main is extremely long.
The actual work, i.e. the networking part of the program, can be split off to a function that is very similar to main, except that it takes properly parsed and validated arguments:
int main(int argc, char *argv[])
{
// handle arguments
return serve(port, n_lists);
}
int serve(int port, int n_lists)
{
// do actual work
}
As for error handling: if this code is not meant to be a library, you can get away with just killing the calling process when something goes wrong in a function, no matter how deep down in the call chain it is; that is in fact recommended practice (Kernighan & Pike, The Practice of Programming). Just make sure you factor out the actual error printing routines in something like
void error(char const *details)
{
extern char const *progname; // preferably, put this in a header
fprintf(stderr, "%s: error (%s): %s\n", progname, details, strerror(errno));
exit(1);
}
to get consistent error messages. (You might want to check out err(3) on Linux and BSD and maybe emulate that interface on other platforms.)
You can also try to factor out those operations that simply can't go wrong or are just calling a few system calls with some fool-proof setup, since those make for easily reusable components.
Leave as is? A bit of setup at the start of main doesn't constitute a problem, IMO. Start refactoring after things are set up.
Isn't that a sign that you are refactoring for the sake of refactoring ?
Anyway, regarding the "let's initialise sockfd and s_addr in one go", you can always
create a structure, and pass a pointer to it :
struct app_ctx {
int init_stage;
int sock_fd;
struct sockaddr_in myaddr;
...
}
Then you pass a pointer to an instance of this structure to all your "do one thing at a time" functions, and return error code.
At cleanup time, you do the same thing and pass the same structure.

Resources