Skip to content

Instantly share code, notes, and snippets.

@yzyzsun
Created November 27, 2018 10:08
Show Gist options
  • Save yzyzsun/52ed1799b24bda08f3c0ae534356a99a to your computer and use it in GitHub Desktop.
Save yzyzsun/52ed1799b24bda08f3c0ae534356a99a to your computer and use it in GitHub Desktop.
Simple Web Server
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define SERV_PORT 4746
#define BACKLOG 10
#define DATA_LEN 100000
#define METHOD_LEN 8
#define TYPE_LEN 20
#define PATH_LEN 100
#define FIELD_LEN 100
void not_found(int client) {
char buf[] = "HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\nContent-Length: 9\r\n\r\nNot Found";
send(client, buf, strlen(buf), 0);
}
void not_implemented(int client) {
char buf[] = "HTTP/1.1 501 Not Implemented\r\nContent-Type: text/html\r\nContent-Length: 15\r\n\r\nNot Implemented";
send(client, buf, strlen(buf), 0);
}
void *worker(void *arg) {
int client = *(int *)arg;
for (;;) {
char request[DATA_LEN];
int len = recv(client, request, sizeof(request), 0);
request[len] = 0;
if (len <= 0) {
shutdown(client, SHUT_RDWR);
return 0;
}
char method[METHOD_LEN];
char path[PATH_LEN] = "public";
sscanf(request, "%s%s", method, path + strlen(path));
if (path[strlen(path) - 1] == '/') strcat(path, "index.html");
printf("%s %s\n", method, path);
if (strcmp(method, "GET") == 0) {
FILE *fp = fopen(path, "r");
if (fp) {
char buf[DATA_LEN] = "HTTP/1.1 200 OK\r\n";
if (strcmp(path + strlen(path) - 4, ".jpg") == 0) {
strcat(buf, "Content-Type: image/jpeg\r\n");
} else {
strcat(buf, "Content-Type: text/html\r\n");
}
fseek(fp, 0, SEEK_END);
long fsize = ftell(fp);
rewind(fp);
sprintf(buf + strlen(buf), "Content-Length: %ld\r\n\r\n", fsize);
int offset = strlen(buf);
fread(buf + offset, 1, fsize, fp);
send(client, buf, offset + fsize, 0);
fclose(fp);
} else {
not_found(client);
}
} else if (strcmp(method, "POST") == 0) {
if (strcmp(path, "public/dopost") == 0) {
char buf[DATA_LEN] = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n";
char *body = strstr(request, "\r\n\r\n");
body += 4;
char login[FIELD_LEN], pass[FIELD_LEN];
sscanf(body, "login=%[^&]&pass=%s", login, pass);
printf("Login attempt using %s:%s\n", login, pass);
char *response;
if (strcmp(login, "3140104746") == 0 && strcmp(pass, "4746") == 0) {
response = "Login succeeded";
} else {
response = "Login failed";
}
sprintf(buf + strlen(buf), "Content-Length: %lu\r\n\r\n%s", strlen(response), response);
send(client, buf, strlen(buf), 0);
} else {
not_found(client);
}
} else {
not_implemented(client);
}
}
}
int main(int argc, char *argv[]) {
int sock = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(SERV_PORT);
bind(sock, (const struct sockaddr *)&servaddr, sizeof(servaddr));
listen(sock, BACKLOG);
printf("HTTP Server running on port %d\n", SERV_PORT);
for (;;) {
int client = accept(sock, NULL, NULL);
if (client < 0) continue;
struct sockaddr_in connaddr;
socklen_t connaddr_len = sizeof(connaddr);
getpeername(client, (struct sockaddr *)&connaddr, &connaddr_len);
printf("Connection from %s:%hu\n",
inet_ntoa(connaddr.sin_addr), ntohs(connaddr.sin_port));
pthread_t tid;
pthread_create(&tid, NULL, worker, &client);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "tcp_common.h"
void *worker(void *arg) {
int sockfd = *(int *)arg;
for (;;) {
char reply[DATA_LEN];
ssize_t length = recv(sockfd, reply, sizeof(reply), 0);
if (length <= 0) {
puts("Lose connection to server");
shutdown(sockfd, SHUT_RDWR);
return 0;
}
while (reply[strlen(reply) - 1] == '\n') reply[strlen(reply) - 1] = 0;
switch (reply[0]) {
case TYPE_MSG: {
int clino, offset;
sscanf(reply + 1, "%d\n%n", &clino, &offset);
offset++;
printf("--- Message From No.%d ---\n", clino);
puts(reply + offset);
puts("--- Message End ---");
break;
}
case TYPE_SUC:
puts("--- Server Reply Begin ---");
puts(reply + 1);
puts("--- Server Reply End ---");
break;
case TYPE_ERR:
puts("--- Server Error Begin ---");
puts(reply + 1);
puts("--- Server Error End ---");
break;
}
}
}
int request(int sockfd, char type, char *msg) {
char data[strlen(msg) + 2];
data[0] = type;
data[1] = 0;
strcat(data, msg);
return send(sockfd, data, sizeof(data), 0);
}
int main(int argc, char *argv[]) {
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
for (;;) {
if (servaddr.sin_family) {
printf("You have connected to %s:%hd. Please select one option from the list below:\n", inet_ntoa(servaddr.sin_addr), ntohs(servaddr.sin_port));
puts("1. Disconnect from the server.");
puts("2. Retrieve the server time.");
puts("3. Retrieve the server name.");
puts("4. Retrieve the list of clients.");
puts("5. Send a message.");
puts("6. Quit.");
int number;
scanf("%d", &number);
switch (number) {
case 1:
shutdown(sockfd, SHUT_RDWR);
sockfd = socket(PF_INET, SOCK_STREAM, 0);
memset(&servaddr, 0, sizeof(servaddr));
break;
case 2:
request(sockfd, TYPE_TIME, "");
break;
case 3:
request(sockfd, TYPE_NAME, "");
break;
case 4:
request(sockfd, TYPE_LIST, "");
break;
case 5: {
while (getchar() != '\n');
char msg[DATA_LEN];
puts("Enter the number of client to which you want to send the message:");
fgets(msg, DATA_LEN, stdin);
puts("Enter the message to send:");
fgets(msg + strlen(msg), DATA_LEN - strlen(msg), stdin);
request(sockfd, TYPE_SEND, msg);
break;
}
default:
shutdown(sockfd, SHUT_RDWR);
return 0;
}
} else {
puts("You have not connected to a server. Please select one option from the list below:");
puts("1. Connect.");
puts("2. Quit.");
int number;
scanf("%d", &number);
switch (number) {
case 1:
puts("Enter the IP address and port number: (e.g. 127.0.0.1:80)");
char ipaddr[IPADDR_LEN];
in_port_t port;
scanf("\n%[^:]:%hu", ipaddr, &port);
servaddr.sin_family = PF_INET;
inet_aton(ipaddr, &servaddr.sin_addr);
servaddr.sin_port = htons(port);
int ret = connect(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr));
if (ret == 0) {
pthread_t tid;
pthread_create(&tid, NULL, worker, &sockfd);
} else {
memset(&servaddr, 0, sizeof(servaddr));
puts("Connection failed");
}
break;
default:
return 0;
}
}
}
}
#pragma once
#define TYPE_TIME 100
#define TYPE_NAME 101
#define TYPE_LIST 102
#define TYPE_SEND 103
#define TYPE_SUC 104
#define TYPE_ERR 105
#define TYPE_MSG 106
#define IPADDR_LEN 16
#define DATA_LEN 1024
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <sys/utsname.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "tcp_common.h"
#define SERV_PORT 4746
#define BACKLOG 10
struct connection {
pthread_t tid;
int sock;
char ipaddr[IPADDR_LEN];
in_port_t port;
bool connected;
} conn[BACKLOG];
int conn_count = 0;
void *worker(void *arg) {
int index = *(int *)arg;
int connfd = conn[index].sock;
for (;;) {
char request[DATA_LEN];
int length = recv(connfd, request, sizeof(request), 0);
if (length <= 0) {
conn[index].connected = false;
shutdown(connfd, SHUT_RDWR);
return 0;
}
char reply[DATA_LEN];
char type = request[0];
switch (type) {
case TYPE_TIME: {
reply[0] = TYPE_SUC;
time_t t = time(NULL);
strcpy(reply + 1, ctime(&t));
break;
}
case TYPE_NAME: {
reply[0] = TYPE_SUC;
struct utsname sysinfo;
uname(&sysinfo);
strcpy(reply + 1, sysinfo.nodename);
break;
}
case TYPE_LIST: {
reply[0] = TYPE_SUC;
int offset;
sprintf(reply + 1, "No.\tIP address\tPort\tConnected\n%n", &offset);
offset++;
for (int i = 0; i < conn_count; i++) {
int count;
sprintf(reply + offset, "%d\t%s\t%hu\t%d\n%n",
i, conn[i].ipaddr, conn[i].port, conn[i].connected, &count);
offset += count;
}
break;
}
case TYPE_SEND: {
int clino, offset;
sscanf(request + 1, "%d\n%n", &clino, &offset);
offset++;
if (clino < conn_count) {
char msg[DATA_LEN];
msg[0] = TYPE_MSG;
sprintf(msg + 1, "%d\n%s", index, request + offset);
ssize_t ret = send(conn[clino].sock, msg, strlen(msg) + 1, 0);
if (ret > 0) {
reply[0] = TYPE_SUC;
strcpy(reply + 1, "Sent successfully");
} else {
reply[0] = TYPE_ERR;
strcpy(reply + 1, "Sending failed");
}
} else {
reply[0] = TYPE_ERR;
strcpy(reply + 1, "Client number not found");
}
break;
}
}
send(connfd, reply, strlen(reply) + 1, 0);
}
}
int main(int argc, char *argv[]) {
int sockfd = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = INADDR_ANY;
servaddr.sin_port = htons(SERV_PORT);
bind(sockfd, (const struct sockaddr *)&servaddr, sizeof(servaddr));
listen(sockfd, BACKLOG);
for (;;) {
int connfd = accept(sockfd, NULL, NULL);
if (connfd < 0) continue;
struct sockaddr_in connaddr;
socklen_t connaddr_len = sizeof(connaddr);
getpeername(connfd, (struct sockaddr *)&connaddr, &connaddr_len);
int index = conn_count;
conn[index].sock = connfd;
strcpy(conn[index].ipaddr, inet_ntoa(connaddr.sin_addr));
conn[index].port = ntohs(connaddr.sin_port);
conn[index].connected = true;
printf("Connection from %s:%hu\n", conn[index].ipaddr, conn[index].port);
pthread_create(&conn[index].tid, NULL, worker, &index);
conn_count++;
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment