Skip to content

Commit e4bf4d5

Browse files
committed
simple sftp server done.
0 parents  commit e4bf4d5

File tree

13 files changed

+1261
-0
lines changed

13 files changed

+1261
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
*.o
2+
file_server

Makefile

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
CFLAGS=-std=c99 -O2 -w
2+
all: file_server
3+
file.o: file.c file.h
4+
gcc $(CFLAGS) file.c -c -o file.o
5+
poll.o: poll.c poll.h
6+
gcc $(CFLAGS) poll.c -c -o poll.o
7+
coroutine.o: coroutine.c coroutine.h switch.S
8+
gcc $(CFLAGS) coroutine.c -c -o coroutine.o
9+
switch.o: switch.S
10+
gcc $(CFLAGS) switch.S -c -o switch.o
11+
main.o: main.c
12+
gcc $(CFLAGS) main.c -c -o main.o
13+
listen_server.o: listen_server.c listen_server.h
14+
gcc $(CFLAGS) listen_server.c -c -o listen_server.o
15+
sftp.o: sftp.c
16+
gcc $(CFLAGS) sftp.c -c -o sftp.o
17+
file_server: file.o poll.o coroutine.o sftp.o switch.o main.o listen_server.o
18+
gcc $(CFLAGS) file.o poll.o coroutine.o sftp.o switch.o listen_server.o main.o -o file_server
19+
.PHONY: clean
20+
clean:
21+
rm *.o file_server

coroutine.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#include "coroutine.h"
2+
#include <assert.h>
3+
#include <stdlib.h>
4+
coroutine* current_coroutine;
5+
coroutine* root_coroutine;
6+
int context_switch(context* cfrom, context* cto);
7+
8+
void coroutine_entry(coroutine_func f, void* arg){
9+
f(arg);
10+
current_coroutine->state=1; //tag finished
11+
coroutine_yield(); //as a normal yield.
12+
}
13+
void coroutine_start(coroutine* c, coroutine_func entry, void* arg){
14+
c->caller=0;
15+
c->stack=malloc(STACK_SIZE);
16+
c->state=0;
17+
memset(&c->c_context, 0, sizeof(context));
18+
c->c_context.rsp=c->stack+STACK_SIZE;
19+
// return rip does not matter.
20+
c->c_context.rdi=entry;
21+
c->c_context.rsi=arg;
22+
//*(uint64_t)(c->c_context.rsp+8)=entry; //the entry.
23+
//*(uint64_t)(c->c_context.rsp+16)=arg; //the arg.
24+
c->c_context.rbp=c->stack+STACK_SIZE;
25+
c->c_context.rip=&coroutine_entry;
26+
// everything is ready now, and only requires a trigger.
27+
//printf("%d %d\n", c, c->stack);
28+
}
29+
30+
31+
void coroutine_yield(){
32+
assert(current_coroutine!=root_coroutine); // root coroutine should not be yielded.
33+
context* current_context=&current_coroutine->c_context;
34+
context* parent_context=&current_coroutine->caller->c_context;
35+
coroutine* parent=current_coroutine->caller;
36+
current_coroutine->caller=0;
37+
current_coroutine=parent;
38+
context_switch(current_context, parent_context);
39+
}
40+
41+
42+
int coroutine_await(coroutine* target){
43+
assert(target->caller==0);
44+
assert(target->state==0);
45+
context* current_context=&current_coroutine->c_context;
46+
target->caller=current_coroutine;
47+
current_coroutine=target;
48+
context* new_context=&current_coroutine->c_context;
49+
context_switch(current_context, new_context);
50+
// After some hard work we gain control again.
51+
// now we just free the coroutine.
52+
if(target->state==0){
53+
return 0;
54+
}else{
55+
coroutine_destroy(target);
56+
return 1;
57+
}
58+
}
59+
60+
void coroutine_init(){
61+
// In fact nothing is done.
62+
// root_coroutine is the place to store registers.
63+
root_coroutine=(coroutine*)malloc(sizeof(coroutine));
64+
current_coroutine=root_coroutine;
65+
}
66+
67+
void coroutine_destroy(coroutine* co){
68+
assert(co->state==1);
69+
//printf("%d %d\n", co, co->stack);
70+
free(co->stack);
71+
//printf("stack\n");
72+
free(co);
73+
}

coroutine.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#pragma once
2+
// Let's base our entire work on this coroutine.
3+
// Coroutine makes our life easier.
4+
// For example, when dealing with protocols we no longer need to deal with state machines, but deal with fiber scheduling,
5+
6+
// A coroutine supports three options:
7+
// 1. start: this starts a coroutine.
8+
// 2. yield: throws out a value to outer coroutine.
9+
// 3. await: transfers control to the coroutine. when control is regained,
10+
// a value is fetched from the coroutine.
11+
12+
// Allocate 64KB stack memory.
13+
// This is much cheaper than fork or pthread or something.
14+
#include "sys/types.h"
15+
#include "stdint.h"
16+
#include "setjmp.h"
17+
#define STACK_SIZE 65536
18+
// RAX register is always the scratch.
19+
typedef struct {
20+
uint64_t rip;
21+
uint64_t rsp;
22+
uint64_t rbx;
23+
uint64_t rcx;
24+
uint64_t rdx;
25+
uint64_t rsi;
26+
uint64_t rdi;
27+
uint64_t rbp;
28+
uint64_t r8;
29+
uint64_t r9;
30+
uint64_t r10;
31+
uint64_t r11;
32+
uint64_t r12;
33+
uint64_t r13;
34+
uint64_t r14;
35+
uint64_t r15;
36+
} context;
37+
38+
typedef struct tag_coroutine{
39+
struct tag_coroutine* caller;
40+
context c_context;
41+
uint8_t* stack;
42+
int state;
43+
jmp_buf exception_env;
44+
} coroutine;
45+
#define coroutine_catch (setjmp(current_coroutine->exception_env))
46+
#define coroutine_throw {do{longjmp(current_coroutine->exception_env, 1);}while(0);}
47+
extern coroutine* current_coroutine;
48+
extern coroutine* root_coroutine;
49+
50+
typedef void (*coroutine_func)(void*);
51+
52+
// Set the main process as the outer-most coroutine.
53+
void coroutine_init();
54+
void coroutine_start(coroutine* c, coroutine_func entry, void* arg);
55+
void coroutine_yield();
56+
int coroutine_await();
57+
void coroutine_destroy(coroutine* co);

0 commit comments

Comments
 (0)