diff --git a/.gitignore b/.gitignore index dbe9c82..f218f66 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,5 @@ -.vscode/ \ No newline at end of file +*vsidx +*.opendb +.vs +out +CMakePresets.json \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index 98a9c05..dcb1e58 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -11,7 +11,8 @@ "_UNICODE" ], "windowsSdkVersion": "10.0.22621.0", - "intelliSenseMode": "windows-msvc-x64" + "intelliSenseMode": "windows-msvc-x64", + "configurationProvider": "ms-vscode.cmake-tools" } ], "version": 4 diff --git a/System_Calls/readme.md b/System_Calls/readme.md index ee98ac2..ce519d0 100644 --- a/System_Calls/readme.md +++ b/System_Calls/readme.md @@ -79,3 +79,13 @@ Below are the system calls that can be used to access network functionality. freeaddrinfo(servinfo); // free the linked list ``` + +* **socket() :** + + * Purpose : + + Assign a *file descriptor* for accessing OS resources to access network. Defines the type connection it would make to other host. + + * Function Prototype : + + diff --git a/examples/tcp_client.c b/examples/tcp_client.c new file mode 100644 index 0000000..f41b976 --- /dev/null +++ b/examples/tcp_client.c @@ -0,0 +1,95 @@ +/* +* client.c -- a stream socket client demo +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define PORT "3490" // the port client will be connecting to + +#define MAXDATASIZE 100 // 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[]){ + int sockfd, numbytes; + char buf[MAXDATASIZE]; + struct addrinfo hints, *servinfo, *p; + int rv; + char s[INET6_ADDRSTRLEN]; + + if(argc != 2){ + fprintf(stderr, "usage: client hostname\n"); + exit(1); + } + + + 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_addlen) == -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 + + if((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1){ + perror("recv"); + exit(1); + } + + buf[numbytes] = '\0'; + + printf("client: received '%s' \n", buf); + + close(sockfd); + + return 0; +} \ No newline at end of file diff --git a/examples/tcp_server.c b/examples/tcp_server.c new file mode 100644 index 0000000..177ebd3 --- /dev/null +++ b/examples/tcp_server.c @@ -0,0 +1,135 @@ +/* +* server.c -- a stream socket server demo +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PORT "3490" // the port users will be connecting to + +#define BACKLOG 10 // how many pending connections queue will hold + +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; + + 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, PORT, &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 (setsocket(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { + perror("setsockopt"); + exit(1); + } + + if (bind(sockfd, p->ai_addr, p->ai_addlen) == -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 + if( send(new_fd, "Hello, world!", 13, 0) == -1) + perror("send"); + + close(new_fd); + exit(0); + } + + close(new_fd); // parent doesn't need this + } + + return 0; +} \ No newline at end of file diff --git a/examples/udp_client.c b/examples/udp_client.c new file mode 100644 index 0000000..f51fb2e --- /dev/null +++ b/examples/udp_client.c @@ -0,0 +1,67 @@ +/* +* udp_client -- a datagram "client" demo +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define SERVERPORT "4950" // the port users will be connecting to + +int main(int argc, char* argv[]){ + + int sockfd; + struct addrinfo hints, *servinfo, *p; + int rv; + int numbytes; + + if( argc != 3){ + fprintf(stderr, "usage: talker hostname message\n"); + exit(1); + } + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET6; // set to AF_INET to use IPv4 + hints.ai_socktype = SOCK_DGRAM; + + if((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0){ + fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); + return 1; + } + + // loop throught all the results and make a socket + for( p = servinfo; p != NULL ; p = p->ai_next){ + if((sockfd = socket(p->ai_family, p->ai_socktype, + p->ai_protocol)) == -1){ + perror("talker: socket"); + continue; + } + + break; + } + + if( p == NULL ){ + fprintf(stderr, "talker: failed to create socket\n"); + return 2; + } + + if((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, + p->ai_addr, p->ai_addrlen)) == -1 ){ + perror("talker: sendto"); + exit(1); + } + + freeaddrinfo(servinfo); + + printf("talker: sent %d bytes to %s\n", numbytes, argv[1]); + close(sockfd); + + return 0; +} \ No newline at end of file diff --git a/examples/udp_server.c b/examples/udp_server.c new file mode 100644 index 0000000..f2193e2 --- /dev/null +++ b/examples/udp_server.c @@ -0,0 +1,97 @@ +/* +* listener.c -- a datagram sockets "server" demo +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MYPORT "4950" // the port users will be connecting to + +#define MAXBUFLEN 100 + +// 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; + struct addrinfo hints, *servinfo, *p; + int rv; + int numbytes; + struct sockaddr_storage their_addr; + char buf[MAXBUFLEN]; + socklen_t addr_len; + char s[INET6_ADDRSTRLEN]; + + memset(&hints, 0, sizeof hints); + hints.ai_family = AF_INET6; // set to AF_INET to use IPv4 + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_PASSIVE; // use my IP + + 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; + } + + freeaddrinfo(servinfo); + + printf("listener: waiting to recvfrom...\n"); + + addr_len = sizeof their_addr; + if((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1, 0, + (struct sockaddr *)&their_addr, &addr_len)) == -1){ + + perror("recvfrom"); + exit(1); + } + + printf("listener: got packet from %s\n", + inet_ntop(their_addr.ss_family, + get_in_addr((struct sockaddr *)&their_addr), + s, sizeof s)); + + + printf("listener: packet is %d bytes long\n", numbytes); + buf[numbytes] = '\0'; + printf("listener: packet contains \"%s\"\n", buf); + + close(sockfd); + return 0; +} \ No newline at end of file