From bbdbb22c8e6461123d339d373446c4c7eae21f1d Mon Sep 17 00:00:00 2001 From: Hizenberg Date: Fri, 13 Sep 2024 23:54:25 +0530 Subject: [PATCH] Fundatmentals finished --- System_Calls/readme.md | 602 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 602 insertions(+) diff --git a/System_Calls/readme.md b/System_Calls/readme.md index ce519d0..f859ecd 100644 --- a/System_Calls/readme.md +++ b/System_Calls/readme.md @@ -88,4 +88,606 @@ Below are the system calls that can be used to access network functionality. * Function Prototype : + ``` + #include + #include + + int socket(int domain, int type, int protocol); + ``` + + 1. domain : + + Type : `int` + + Value : `PF_INET` or `PF_INET6` + + Purpose : Used to specify the Protocol family we would like to use. + + > [!IMPORTANT] + > The value of `PF_INET` and `AF_INET` are same and they are used + > interchangably. **PF** stands for *Protocol family* and **AF** stands + > stands for *Address family*. + 2. type : + + Type : `int` + + Value : `SOCK_STREAM` or `SOCK_DGRAM` + + Purpose : Used to signify type of socket we want to create. + (Connection or Connection-less). + + 3. protocol : + + Type : `int` + + Purpose : Signifies either `TCP` or `UDP` protocol is being used for communication. + + * Return Type : + + Returns' an integer which signify an `fd` or -1 on error and global variable *errno* is set to the error's value . + + * **Code Snippet** + + ``` + int s; + struct addrinfo hints, *res; + + // do the lookup + // [pretend we already filled out the "hints" struct] + getaddrinfo("www.example.com", "http", &hints, &res); + + // remember, do the error-checking on getaddrinfo(), + // walk the "res" linked list for valid entries. + + s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + ``` + +* **bind() :** + + * Purpose : + + It's used for connecting socket fd with port of local machine. + + * Function prototype : + + ``` + #include + #include + + int bind(int sockfd, struct sockaddr *my_addr, int addrlen); + ``` + + 1. sockfd : + + Type : `int` + + Value : integer value representing socket fd. + + Purpose : sockfd to bind to a port. + + 2. my_addr : + + Type : `struct sockaddr *` + + Value : Holding port number information. + + Purpose : port number to bind to sockfd. + + 3. addrlen : + + Type : `int` + + Value : length of the `struct sockaddr`. + + * Return Type : + + returns -1 on error and sets **errno** to the error's value. + + >[!IMPORTANT] + > The below code snippet is w.r.t old way of using bind function. + > The new way of doing the same is to use `getaddrinfo()` for ease. + + ``` + // !!! THIS IS THE OLD WAY !!! + + int sockfd; + struct sockaddr_in my_addr; + + sockfd = socket(PF_INET, SOCK_STREAM, 0); + + my_addr.sin_family = AF_INET; + my_addr.sin_port = htons(MYPORT); // short, network byte order + my_addr.sin_addr.s_addr = inet_addr("10.12.110.57"); + memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero); + + bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr); + ``` + + >[!NOTE] + > Sometimes binding to a port maybe fail due to its live bond with a free + > socket and can lead to error. To avoid this below code snippet can be + > userful. + > + > ``` + > int yes = 1; + > // char yes = '1'; // Solaris people use this + > + > // lose the pesky "Address already in use" error message + > if( setsockopt(listener,SOL_SOCKET, + > SO_REUSEADDR, &yes, sizeof yes) == -1){ + > perror("setsockopt"); + > exit(1); + > } + > ``` + +* **connect() :** + + * Purpose : + + To connect to a remote host. + + * Function prototype : + + ``` + #include + #include + + int connect(int sockfd, struct sockaddr *serv_addr, int addrlen); + ``` + + 1. sockfd : + + Type : `int` + + Value : socket fd, as returned by the `socket()` call. + + 2. serv_addr : + + Type : `struct sockaddr *` + + Value : containing destination port and IP address. + + 3. addrlen : + + Type : `int` + + Value : length `struct sockaddr` in bytes. + + * Return : + + It'll return -1 on error and set the variable `errno`. + + * Code snippet : + + ``` + struct addrinfo hints, *res; + int sockfd; + + // first, load up address structs with getaddrinfo(): + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + + getaddrinfo("www.example.com", "3490", &hints, &res); + + // make a socket: + + sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + + // connect! + + connect(sockfd, res->ai_addr, res->ai_addrlen); + ``` + +* **listen() :** + + * Purpose : + + Connect to incoming connection from remote host computers. + + * Function prototype : + + ``` + int listen(int sockfd, int backlog); + ``` + + 1. sockfd : + + Type : `int` + + Value : socket fd, as returned by the `socket()` call. + + 2. backlog : + + Type : `int` + + Value : number of connection allowed on the incoming queue. + + * Return : + + It'll return -1 on error and set the variable `errno`. + + * Code Snippet : + + ``` + getaddrinfo(); + socket(); + bind(); + listen(); + /* accept() goes here */ + ``` + +* **accept() :** + + * Purpose : + + Accept connection request pending in the waiting queue. + + * Function Prototype : + + ``` + #include + #include + + int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen); + ``` + + 1. sockfd : + + Types : `int` + + Value : *sockfd* is the listening socket descriptor. + + 2. addr : + + Type : `struct sockaddr *` + + Value : pointer to a local `struct sockaddr_storage`. This is where the information about the incoming connection will go(and with it we can determine which host is calling us from which port). + + 3. addrlen : + + Type : `int` + + Value : equal to value sizeof(struct sockaddr_storage). accept() will not put more than that many bytes into addr. If it puts fewer in, it'll change the value of addrlen to reflect that. + + * Return value : + + returns -1 and set `errno` if error occurs. + + * Code Snippet : + + ``` + #include + #include + #include + #include + + #define MYPORT "3490" // the port users will be connecting to + #define BACKLOG 10 // how many pending connections queue will hold + + int main(){ + + struct sockaddr_storage their_addr; + socklen_t addr_size; + struct addrinfo hints, *res; + int sockfd, new_fd; + + // !! don't forget your error checking for these calls !! + + // first, load up address structs with getaddrinfo(); + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_UNSPEC; // use IPv4 or IPv6, whichever + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; // fill in my IP for me + + getaddrinfo(NULL, MYPORT, &hints, &res); + + // make a socket, bind it, and listen on it: + + sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + bind(sockfd, res->ai_addr, res->ai_addrlen); + listen(sockfd, BACKLOG); + + // now accept an incoming connection: + + addr_size = sizeof their_addr; + new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size); + + // ready to communicate on socket descriptor new_fd! + } + ``` + + >[!NOTE] + > new_fd will be used for send() and recv() calls. + +* **send() :** + + * Purpose : + + Used for communication between two connections. The communication can over stream sockets or connected datagram sockets. + + * Function Prototype : + + ``` + int send(int socfd, const void *msg, int len, int flags); + ``` + + 1. sockfd : + + Type : `int` + + Value : *sockfd* is the socket descriptor you want to send data to(whether it's the one returned by socket() or the one you got with accept()). + + 2. msg : + + Type : `const void *` + + Value : pointer to data we want to send in form of byte array. + + 3. len : + + Type : `int` + + Value : Length of byte array. + + 4. flag : + + Type : `int` + + Value : set to 0. + + * Return type: + + returns the number of bytes actually sent out - *this might be less than the number you told it to send!*. Again, -1 is returned on error, and `errno` is set to the error number. + + * Code Snippet : + + ``` + char *msg = "Beej was here!"; + int len, bytes_sent; + + len = strlen(msg); + bytes_sent = send(sockfd, msg, len, 0); + ``` + +* **recv() :** + + * Purpose : + + To receive data from the remote machine, which may attempt to send data. + + * Function prototype : + + ``` + int recv(int sockfd, void *buf, int len, int flags); + ``` + + 1. sockfd : + + Type : `int` + + Value : Socket desriptor to read from. + + 2. buf : + + Type : `void *` + + Value : buffer to read the information into. + + 3. len : + + Type : `int` + + Value : maximum length of buffer specified. + + 4. flags : + + Type : `int` + + Value : set to 0. + + * Return type : + + Number of bytes actually read into the buffer or -1 on error. recv() can return 0 when the remote side has closed the connection. + +* **sendto() :** + + * Purpose : + + To send data to remote connection without forming any connection beforehand. + + * Function Prototype : + + ``` + int sendto(int sockfd, const void *msg, int len, unsigned int flags, + const struct sockaddr *to, socklen_t tolen); + ``` + + 1. sockfd : + + Type : `int` + + Value : fd which maintain connection with remote machine. + + 2. msg : + + Type : `const void*` + + Value : buffer which stores the data which need to be transferred. + + 3. len : + + Type : `int` + + Value : Length of the buffer + + 4. flags : + + Type : `int` + + Value : set it to zero + + 5. to : + + Type : `struct sockaddr *` + + Value : Containing the address we want the send data to. + + 6. tolen : + + Type : `socklen_t` + + Value : `int` deep down, is equal to sizeof(struct sockaddr_storage). + +* **recvfrom() :** + + * Purpose : + + It receive data by remote machine which choose udp mode of communication. + + * Function Prototype : + + ``` + int recvfrom(int sockfd, void *buf, int len, unsigned int flags, + struct sockaddr *from, int *fromlen); + ``` + + 1. sockfd : + + Type : `int` + + Value : fd which maintain connection with remote machine. + + 2. buf : + + Type : `void *` + + Value : buffer which will stores the data that would be received. + + 3. len : + + Type : `int` + + Value : Length of the buffer + + 4. flags : + + Type : `int` + + Value : set it to zero + + 5. from : + + Type : `struct sockaddr *` + + Value : contains the address of sending machine. + + 6. fromlen : + + Type : `int` + + Value : equal to sizeof(struct sockaddr_storage) + + * Returns : + + returns number of bytes received, or -1 on error and set `errno`. + +* **close() :** + + * Purpose : + + To close the socket and prevent any further communication. + + * Function Prototype : + + ``` + close(sockfd); + ``` + +* **shutdown() :** + + * Purpose : + + It gives more control over how the socket closes. It allows you to cut off communication in a certain direction, or both ways. If applied on unconnected datagram sockets, it will simply make socket unavailable to use. + + * Function Prototype : + + ``` + int shutdown(int sockfd, int how); + ``` + + 1. sockfd : + + which socket to close. + + 2. how : + + how can have following value :- + + * 0 - Further receives are disallowed. + * 1 - Further sends are disallowed. + * 2 - Further sends and receives are disallowed(like close()). + + * Returns: + + returns 0 on success or -1 on failure. + +> [!NOTE] +> `shutdown()` doesn't actually close the file descriptor -- it just +> changes its usability. To free socket descriptor, you need to use +> `close()`. + +* **getpeername() :** + + * Purpose : + + It tells us who is at the other end of a connected stream socket. + + * Function Prototype : + + ``` + #include + + int getpeername(int sockfd, struct sockaddr *addr, int *addrlen); + ``` + + 1. sockfd : + + Descriptor of connected stream socket. + + 2. addr : + + Holds the address of the remote connection. + + 3. addrlen : + + Equal to the sizeof(struct sockaddr). + + * Returns : + + Returns -1 on error and sets errno accordingly. + +* **gethostname() :** + + * Purpose : + + Gets name of the computer that running our program. + + * Function Prototype : + + ``` + #include + + int gethostname(char *hostname, size_t size); + ``` + + 1. hostname : + + buffer to contain the hostname. + + 2. size : + + size of the buffer. \ No newline at end of file