tcpsock.c
上传用户:hepax88
上传日期:2007-01-03
资源大小:1101k
文件大小:10k
源码类别:

TCP/IP协议栈

开发平台:

Visual C++

  1. #include "global.h"
  2. #include "tcp.h"
  3. #include "socket.h"
  4. #include "usock.h"
  5. static void s_trcall(struct tcb *tcb,int32 cnt);
  6. static void s_tscall(struct tcb *tcb,int old,int new);
  7. static void s_ttcall(struct tcb *tcb,int32 cnt);
  8. static void trdiscard(struct tcb *tcb,int32 cnt);
  9. static void autobind(struct usock *up);
  10. uint16 Lport = 1024;
  11. int
  12. so_tcp(struct usock *up,int protocol)
  13. {
  14. up->type = TYPE_TCP;
  15. return 0;
  16. }
  17. int
  18. so_tcp_listen(struct usock *up,int backlog)
  19. {
  20. struct sockaddr_in *local;
  21. struct socket lsock;
  22. if(up->name == NULL)
  23. autobind(up);
  24. local = (struct sockaddr_in *)up->name;
  25. lsock.address = local->sin_addr.s_addr;
  26. lsock.port = local->sin_port;
  27. up->cb.tcb = open_tcp(&lsock,NULL,
  28.  backlog ? TCP_SERVER:TCP_PASSIVE,0,
  29. s_trcall,s_ttcall,s_tscall,up->tos,up->index);
  30. return 0;
  31. }
  32. int
  33. so_tcp_conn(struct usock *up)
  34. {
  35. int s;
  36. struct tcb *tcb;
  37. struct socket lsock,fsock;
  38. struct sockaddr_in *local,*remote;
  39. if(up->name == NULL){
  40. autobind(up);
  41. }
  42. if(checkipaddr(up->peername,up->peernamelen) == -1){
  43. errno = EAFNOSUPPORT;
  44. return -1;
  45. }
  46. s = up->index;
  47. /* Construct the TCP-style ports from the sockaddr structs */
  48. local = (struct sockaddr_in *)up->name;
  49. remote = (struct sockaddr_in *)up->peername;
  50. if(local->sin_addr.s_addr == INADDR_ANY)
  51. /* Choose a local address */
  52. local->sin_addr.s_addr = locaddr(remote->sin_addr.s_addr);
  53. lsock.address = local->sin_addr.s_addr;
  54. lsock.port = local->sin_port;
  55. fsock.address = remote->sin_addr.s_addr;
  56. fsock.port = remote->sin_port;
  57. /* Open the TCB in active mode */
  58. up->cb.tcb = open_tcp(&lsock,&fsock,TCP_ACTIVE,0,
  59.  s_trcall,s_ttcall,s_tscall,up->tos,s);
  60. /* Wait for the connection to complete */
  61. while((tcb = up->cb.tcb) != NULL && tcb->state != TCP_ESTABLISHED){
  62. if(up->noblock){
  63. errno = EWOULDBLOCK;
  64. return -1;
  65. } else if((errno = kwait(up)) != 0){
  66. return -1;
  67. }
  68. }
  69. if(tcb == NULL){
  70. /* Probably got refused */
  71. FREE(up->peername);
  72. errno = ECONNREFUSED;
  73. return -1;
  74. }
  75. return 0;
  76. }
  77. int
  78. so_tcp_recv(struct usock *up,struct mbuf **bpp,struct sockaddr *from,
  79.  int *fromlen)
  80. {
  81. long cnt;
  82. struct tcb *tcb;
  83. while((tcb = up->cb.tcb) != NULL && tcb->r_upcall != trdiscard
  84.  && (cnt = recv_tcp(tcb,bpp,0)) == -1){
  85. if(up->noblock){
  86. errno = EWOULDBLOCK;
  87. return -1;
  88. } else if((errno = kwait(up)) != 0){
  89. return -1;
  90. }
  91. }
  92. if(tcb == NULL){
  93. /* Connection went away */
  94. errno = ENOTCONN;
  95. return -1;
  96. } else if(tcb->r_upcall == trdiscard){
  97. /* Receive shutdown has been done */
  98. errno = ENOTCONN; /* CHANGE */
  99. return -1;
  100. }
  101. return cnt;
  102. }
  103. int
  104. so_tcp_send(struct usock *up,struct mbuf **bpp,struct sockaddr *to)
  105. {
  106. struct tcb *tcb;
  107. long cnt;
  108. if((tcb = up->cb.tcb) == NULL){
  109. free_p(bpp);
  110. errno = ENOTCONN;
  111. return -1;
  112. }
  113. cnt = send_tcp(tcb,bpp);
  114. while((tcb = up->cb.tcb) != NULL &&
  115.  tcb->sndcnt > tcb->window){
  116. /* Send queue is full */
  117. if(up->noblock){
  118. errno = EWOULDBLOCK;
  119. return -1;
  120. } else if((errno = kwait(up)) != 0){
  121. return -1;
  122. }
  123. }
  124. if(tcb == NULL){
  125. errno = ENOTCONN;
  126. return -1;
  127. }
  128. return cnt;
  129. }
  130. int
  131. so_tcp_qlen(struct usock *up,int rtx)
  132. {
  133. int len;
  134. switch(rtx){
  135. case 0:
  136. len = up->cb.tcb->rcvcnt;
  137. break;
  138. case 1:
  139. len = up->cb.tcb->sndcnt;
  140. break;
  141. }
  142. return len;
  143. }
  144. int
  145. so_tcp_kick(struct usock *up)
  146. {
  147. kick_tcp(up->cb.tcb);
  148. return 0;
  149. }
  150. int
  151. so_tcp_shut(struct usock *up,int how)
  152. {
  153. switch(how){
  154. case 0: /* No more receives -- replace upcall */
  155. up->cb.tcb->r_upcall = trdiscard;
  156. break;
  157. case 1: /* Send EOF */
  158. close_tcp(up->cb.tcb);
  159. break;
  160. case 2: /* Blow away TCB */
  161. reset_tcp(up->cb.tcb);
  162. up->cb.tcb = NULL;
  163. break;
  164. }
  165. return 0;
  166. }
  167. int
  168. so_tcp_close(struct usock *up)
  169. {
  170. if(up->cb.tcb != NULL){ /* In case it's been reset */
  171. up->cb.tcb->r_upcall = trdiscard;
  172. /* Tell the TCP_CLOSED upcall there's no more socket */
  173. up->cb.tcb->user = -1;
  174. close_tcp(up->cb.tcb);
  175. }
  176. return 0;
  177. }
  178. /* TCP receive upcall routine */
  179. static void
  180. s_trcall(struct tcb *tcb,int32 cnt)
  181. {
  182. /* Wake up anybody waiting for data, and let them run */
  183. ksignal(itop(tcb->user),1);
  184. kwait(NULL);
  185. }
  186. /* TCP transmit upcall routine */
  187. static void
  188. s_ttcall(struct tcb *tcb,int32 cnt)
  189. {
  190. /* Wake up anybody waiting to send data, and let them run */
  191. ksignal(itop(tcb->user),1);
  192. kwait(NULL);
  193. }
  194. /* TCP state change upcall routine */
  195. static void
  196. s_tscall(struct tcb *tcb,int old,int new)
  197. {
  198. int s,ns;
  199. struct usock *up,*nup,*oup;
  200. union sp sp;
  201. s = tcb->user;
  202. oup = up = itop(s);
  203. switch(new){
  204. case TCP_CLOSED:
  205. /* Clean up. If the user has already closed the socket,
  206.  * then up will be null (s was set to -1 by the close routine).
  207.  * If not, then this is an abnormal close (e.g., a reset)
  208.  * and clearing out the pointer in the socket structure will
  209.  * prevent any further operations on what will be a freed
  210.  * control block. Also wake up anybody waiting on events
  211.  * related to this tcb so they will notice it disappearing.
  212.  */
  213. if(up != NULL){
  214. up->cb.tcb = NULL;
  215. up->errcodes[0] = tcb->reason;
  216. up->errcodes[1] = tcb->type;
  217. up->errcodes[2] = tcb->code;
  218. ksignal(up,0); /* Wake up anybody waiting */
  219. }
  220. del_tcp(tcb);
  221. break;
  222. case TCP_SYN_RECEIVED:
  223. /* Handle an incoming connection. If this is a server TCB,
  224.  * then we're being handed a "clone" TCB and we need to
  225.  * create a new socket structure for it. In either case,
  226.  * find out who we're talking to and wake up the guy waiting
  227.  * for the connection.
  228.  */
  229. if(tcb->flags.clone){
  230. /* Clone the socket */
  231. ns = socket(AF_INET,SOCK_STREAM,0);
  232. nup = itop(ns);
  233. ASSIGN(*nup,*up);
  234. tcb->user = ns;
  235. nup->cb.tcb = tcb;
  236. /* Allocate new memory for the name areas */
  237. nup->name = mallocw(SOCKSIZE);
  238. nup->peername = mallocw(SOCKSIZE);
  239. nup->index = ns;
  240. /* Store the new socket # in the old one */
  241. up->rdysock = ns;
  242. up = nup;
  243. s = ns;
  244. } else {
  245. /* Allocate space for the peer's name */
  246. up->peername = mallocw(SOCKSIZE);
  247. /* Store the old socket # in the old socket */
  248. up->rdysock = s;
  249. }
  250. /* Load the addresses. Memory for the name has already
  251.  * been allocated, either above or in the original bind.
  252.  */
  253. sp.sa = up->name;
  254. sp.in->sin_family = AF_INET;
  255. sp.in->sin_addr.s_addr = up->cb.tcb->conn.local.address;
  256. sp.in->sin_port = up->cb.tcb->conn.local.port;
  257. up->namelen = SOCKSIZE;
  258. sp.sa = up->peername;
  259. sp.in->sin_family = AF_INET;
  260. sp.in->sin_addr.s_addr = up->cb.tcb->conn.remote.address;
  261. sp.in->sin_port = up->cb.tcb->conn.remote.port;
  262. up->peernamelen = SOCKSIZE;
  263. /* Wake up the guy accepting it, and let him run */
  264. ksignal(oup,1);
  265. kwait(NULL);
  266. break;
  267. default: /* Ignore all other state transitions */
  268. break;
  269. }
  270. ksignal(up,0); /* In case anybody's waiting */
  271. }
  272. /* Discard data received on a TCP connection. Used after a receive shutdown or
  273.  * close_s until the TCB disappears.
  274.  */
  275. static void
  276. trdiscard(struct tcb *tcb,int32 cnt)
  277. {
  278. struct mbuf *bp;
  279. recv_tcp(tcb,&bp,cnt);
  280. free_p(&bp);
  281. }
  282. /* Issue an automatic bind of a local address */
  283. static void
  284. autobind(struct usock *up)
  285. {
  286. struct sockaddr_in local;
  287. local.sin_family = AF_INET;
  288. local.sin_addr.s_addr = INADDR_ANY;
  289. local.sin_port = Lport++;
  290. bind(up->index,(struct sockaddr *)&local,sizeof(struct sockaddr_in));
  291. }
  292. char *
  293. tcpstate(struct usock *up)
  294. {
  295. if(up->cb.tcb == NULL)
  296. return NULL;
  297. return Tcpstates[up->cb.tcb->state];
  298. }
  299. int
  300. so_tcp_stat(struct usock *up)
  301. {
  302. st_tcp(up->cb.tcb);
  303. return 0;
  304. }
  305. struct inet {
  306. struct inet *next;
  307. struct tcb *tcb;
  308. char *name;
  309. int stack;
  310. void (*task)(int,void *,void *);
  311. };
  312. #define NULLINET (struct inet *)0
  313. struct inet *Inet_list;
  314. static void i_upcall(struct tcb *tcb,int oldstate,int newstate);
  315. /* Start a TCP server. Create TCB in listen state and post upcall for
  316.  * when a connection comes in
  317.  */ 
  318. int
  319. start_tcp(uint16 port,char *name,void (*task)(int,void *,void *),int stack)
  320. {
  321. struct inet *in;
  322. struct socket lsocket;
  323. in = (struct inet *)calloc(1,sizeof(struct inet));
  324. lsocket.address = INADDR_ANY;
  325. lsocket.port = port;
  326. in->tcb = open_tcp(&lsocket,NULL,TCP_SERVER,0,NULL,NULL,i_upcall,0,-1);
  327. if(in->tcb == NULL){
  328. free(in);
  329. return -1;
  330. }
  331. in->stack = stack;
  332. in->task = task;
  333. in->name = strdup(name);
  334. in->next = Inet_list;
  335. Inet_list = in;
  336. return 0;
  337. }
  338. /* State change upcall that takes incoming TCP connections */
  339. static void
  340. i_upcall(struct tcb *tcb,int oldstate,int newstate)
  341. {
  342. struct inet *in;
  343. struct sockaddr_in sock;
  344. struct usock *up;
  345. int s;
  346. if(oldstate != TCP_LISTEN)
  347. return; /* "can't happen" */
  348. if(newstate == TCP_CLOSED){
  349. /* Called when server is shut down */
  350. del_tcp(tcb);
  351. return;
  352. }
  353. for(in = Inet_list;in != NULLINET;in = in->next)
  354. if(in->tcb->conn.local.port == tcb->conn.local.port)
  355. break;
  356. if(in == NULLINET)
  357. return; /* not in table - "can't happen" */
  358. /* Create a socket, hook it up with the TCB */
  359. s = socket(AF_INET,SOCK_STREAM,0);
  360. up = itop(s);
  361. sock.sin_family = AF_INET;
  362. sock.sin_addr.s_addr = tcb->conn.local.address;
  363. sock.sin_port = tcb->conn.local.port;
  364. bind(s,(struct sockaddr *)&sock,SOCKSIZE);
  365. sock.sin_addr.s_addr = tcb->conn.remote.address;
  366. sock.sin_port = tcb->conn.remote.port;
  367. up->peernamelen = SOCKSIZE;
  368. up->peername = mallocw(up->peernamelen);
  369. memcpy(up->peername,&sock,SOCKSIZE);
  370. up->cb.tcb = tcb;
  371. tcb->user = s;
  372. /* Set the normal upcalls */
  373. tcb->r_upcall = s_trcall;
  374. tcb->t_upcall = s_ttcall;
  375. tcb->s_upcall = s_tscall;
  376. /* And spawn the server task */
  377. newproc(in->name,in->stack,in->task,s,NULL,NULL,0);
  378. }
  379. /* Close down a TCP server created earlier by inet_start */
  380. int
  381. stop_tcp(uint16 port)
  382. {
  383. struct inet *in,*inprev;
  384. inprev = NULLINET;
  385. for(in = Inet_list;in != NULLINET;inprev=in,in = in->next)
  386. if(in->tcb->conn.local.port == port)
  387. break;
  388. if(in == NULLINET)
  389. return -1;
  390. close_tcp(in->tcb);
  391. free(in->name);
  392. if(inprev != NULLINET)
  393. inprev->next = in->next;
  394. else
  395. Inet_list = in->next;
  396. free(in);
  397. return 0;
  398. }