PageRenderTime 30ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/innbbsd/innd/tcp.pl

https://github.com/wtj/formosa
Perl | 476 lines | 440 code | 10 blank | 26 comment | 39 complexity | 6e1272a002d8b1088c06d5541976e5ca MD5 | raw file
Possible License(s): GPL-2.0
  1. #!/usr/local/bin/perl
  2. package main;
  3. sub tcp'getostype {
  4. chop($_=`uname -a`);
  5. if ( /^SunOS/i ) {
  6. ($os,$host,$ver)=split(/\s+/,$_);
  7. if ( $ver =~ /5\./ ) {
  8. return "Solaris";
  9. } else {
  10. return "BSD";
  11. }
  12. } elsif (/^HP-UX/i) {
  13. return "SYSV";
  14. } elsif (/^AIX/i ) {
  15. return "AIX";
  16. } elsif (/^OSF1/i) {
  17. return "SYSV";
  18. }
  19. }
  20. $tcp'OS = &tcp'getostype();
  21. # /*if ( $OS eq "Solaris") {
  22. # eval 'sub SOCK_STREAM {2;}';
  23. # eval 'sub SOCK_DGRAM {1;}';
  24. # } else { */
  25. eval 'sub SOCK_STREAM {1;}';
  26. eval 'sub SOCK_DGRAM {2;}';
  27. # /*}*/
  28. eval 'sub SOCK_RAW {3;}';
  29. eval 'sub SOCK_RDM {4;}';
  30. eval 'sub SOCK_SEQPACKET {5;}';
  31. eval 'sub SO_DEBUG {0x0001;}';
  32. eval 'sub SO_ACCEPTCONN {0x0002;}';
  33. eval 'sub SO_REUSEADDR {0x0004;}';
  34. eval 'sub SO_KEEPALIVE {0x0008;}';
  35. eval 'sub SO_DONTROUTE {0x0010;}';
  36. eval 'sub SO_BROADCAST {0x0020;}';
  37. eval 'sub SO_USELOOPBACK {0x0040;}';
  38. eval 'sub SO_LINGER {0x0080;}';
  39. eval 'sub SO_OOBINLINE {0x0100;}';
  40. eval 'sub SO_DONTLINGER {(~ &SO_LINGER);}';
  41. eval 'sub SO_SNDBUF {0x1001;}';
  42. eval 'sub SO_RCVBUF {0x1002;}';
  43. eval 'sub SO_SNDLOWAT {0x1003;}';
  44. eval 'sub SO_RCVLOWAT {0x1004;}';
  45. eval 'sub SO_SNDTIMEO {0x1005;}';
  46. eval 'sub SO_RCVTIMEO {0x1006;}';
  47. eval 'sub SO_ERROR {0x1007;}';
  48. eval 'sub SO_TYPE {0x1008;}';
  49. eval 'sub SOL_SOCKET {0xffff;}';
  50. eval 'sub AF_UNSPEC {0;}';
  51. eval 'sub AF_UNIX {1;}';
  52. eval 'sub AF_INET {2;}';
  53. eval 'sub AF_IMPLINK {3;}';
  54. eval 'sub AF_PUP {4;}';
  55. eval 'sub AF_CHAOS {5;}';
  56. eval 'sub AF_NS {6;}';
  57. eval 'sub AF_NBS {7;}';
  58. eval 'sub AF_ECMA {8;}';
  59. eval 'sub AF_DATAKIT {9;}';
  60. eval 'sub AF_CCITT {10;}';
  61. eval 'sub AF_SNA {11;}';
  62. eval 'sub AF_DECnet {12;}';
  63. eval 'sub AF_DLI {13;}';
  64. eval 'sub AF_LAT {14;}';
  65. eval 'sub AF_HYLINK {15;}';
  66. eval 'sub AF_APPLETALK {16;}';
  67. eval 'sub AF_NIT {17;}';
  68. eval 'sub AF_802 {18;}';
  69. eval 'sub AF_OSI {19;}';
  70. eval 'sub AF_X25 {20;}';
  71. eval 'sub AF_OSINET {21;}';
  72. eval 'sub AF_GOSIP {22;}';
  73. eval 'sub AF_MAX {21;}';
  74. eval 'sub PF_UNSPEC { &AF_UNSPEC;}';
  75. eval 'sub PF_UNIX { &AF_UNIX;}';
  76. eval 'sub PF_INET { &AF_INET;}';
  77. eval 'sub PF_IMPLINK { &AF_IMPLINK;}';
  78. eval 'sub PF_PUP { &AF_PUP;}';
  79. eval 'sub PF_CHAOS { &AF_CHAOS;}';
  80. eval 'sub PF_NS { &AF_NS;}';
  81. eval 'sub PF_NBS { &AF_NBS;}';
  82. eval 'sub PF_ECMA { &AF_ECMA;}';
  83. eval 'sub PF_DATAKIT { &AF_DATAKIT;}';
  84. eval 'sub PF_CCITT { &AF_CCITT;}';
  85. eval 'sub PF_SNA { &AF_SNA;}';
  86. eval 'sub PF_DECnet { &AF_DECnet;}';
  87. eval 'sub PF_DLI { &AF_DLI;}';
  88. eval 'sub PF_LAT { &AF_LAT;}';
  89. eval 'sub PF_HYLINK { &AF_HYLINK;}';
  90. eval 'sub PF_APPLETALK { &AF_APPLETALK;}';
  91. eval 'sub PF_NIT { &AF_NIT;}';
  92. eval 'sub PF_802 { &AF_802;}';
  93. eval 'sub PF_OSI { &AF_OSI;}';
  94. eval 'sub PF_X25 { &AF_X25;}';
  95. eval 'sub PF_OSINET { &AF_OSINET;}';
  96. eval 'sub PF_GOSIP { &AF_GOSIP;}';
  97. eval 'sub PF_MAX { &AF_MAX;}';
  98. eval 'sub SOMAXCONN {5;}';
  99. eval 'sub MSG_OOB {0x1;}';
  100. eval 'sub MSG_PEEK {0x2;}';
  101. eval 'sub MSG_DONTROUTE {0x4;}';
  102. eval 'sub MSG_MAXIOVLEN {16;}';
  103. eval 'sub MSG_MAXIOVLEN {16;}';
  104. eval 'sub WNOHANG {1;}';
  105. eval 'sub WUNTRACED {2;}';
  106. #package tcp;
  107. $defaultport = 'nntp';
  108. $defaultserver = 'ccsun35.csie.nctu.edu.tw.';
  109. $ENV{'PATH'}='/bin:/usr/ucb:/usr/etc';
  110. # The Internet TCP client algorithm
  111. # 1. Find the IP address and protocol port number of the server
  112. # with which communication is desired. (gethostbyname,getservbyname)
  113. # 2. Allocate a socket. (socket)
  114. # 3. Specify that the connection needs an arbitary, unsed protocol
  115. # port on the local machine, and allow TCP to choose one. (bind)
  116. # 4. Connect the socket to the server. (connect)
  117. # 5. Communicate with the server using the application-level protocol
  118. # (this usually involves sending requests and awaiting replies)
  119. # 6. close the connection.
  120. #
  121. # reference:
  122. # socket addr, internet style structure for Sun-OS
  123. # include <netinet/in.h>
  124. # struct sockaddr_in {
  125. # short sin_family;
  126. # u_short sin_port;
  127. # struct in_addr sin_addr;
  128. # char sin_zero[8];
  129. # }
  130. # ( 'S n a4 x8' template for perl pack)
  131. # Usage
  132. # &tcpinetclient(FILEHANDLE[,hostname,portno]);
  133. # for example,
  134. # &tcpinetclient(NNTP,'news.csie.nctu.edu.tw','nntp');
  135. # print NNTP "help\r\n";
  136. # $_ = <NNTP>;
  137. # print;
  138. sub main'tcpinetclient {
  139. local(*S,$server,$port)=@_;
  140. $port = $defaultport unless $port;
  141. $server = $defaultserver unless $server;
  142. local($hostname);
  143. chop($hostname = `hostname`);
  144. local($sockaddr)= 'S n a4 x8';
  145. local($name,$aliases,$proto)=getprotobyname('tcp');
  146. local($name,$aliases,$port)=getservbyname($port,'tcp')
  147. unless $port =~ /^\d+$/;
  148. # print "port number in tcpinetclient $port\n";
  149. local($name, $aliases, $type, $len, $thisaddr) = gethostbyname($hostname);
  150. local($name, $aliases, $type, $len, $thataddr) = gethostbyname($server);
  151. if (!socket(S, &main'PF_INET, &main'SOCK_STREAM, $proto)) {
  152. warn "socket: $!";
  153. return 0;
  154. }
  155. local($this) = pack($sockaddr, &main'AF_INET, 0, $thisaddr);
  156. # accept connect from any port (0)
  157. local($that) = pack($sockaddr, &main'AF_INET, $port, $thataddr);
  158. # bind(S, $this) || die "bind to $hostname: $!";
  159. if (connect(S, $that) )
  160. {
  161. select(S); $| = 1; select(STDOUT);
  162. return 1;
  163. } else {
  164. warn "connect to $port: $!";
  165. return 0;
  166. }
  167. }
  168. # reference: socket for unix domain in Sun-OS
  169. # include <socket.h>
  170. # struct sockaddr {
  171. # u_short sa_family;
  172. # char sa_data[14];
  173. # }
  174. # ('S a14' perl template for perl)
  175. # usage
  176. # &tcpunixclient(FILEHANDLE,path);
  177. # for example,
  178. # &tcpunixclient(LOCAL,"/tmp/unixsock$$");
  179. #$defaultpath="/tmp/unixsock$$";
  180. $defaultpath='/tmp/sample';
  181. # only 14 chars can be used
  182. sub main'tcpunixclient {
  183. local(*S,$path)=@_;
  184. $path = $defaultpath unless $path;
  185. local($sockaddr)= 'S a14';
  186. socket(S, &PF_UNIX, &SOCK_STREAM, 0) || die "socket: $!";
  187. $that = pack($sockaddr, &AF_INET, $path);
  188. connect(S, $that) || die "connect to $path: $!";
  189. select(S); $| = 1; select(STDOUT);
  190. 1;
  191. }
  192. # o Interactive, Connection-Orientd Server
  193. # o Interactive, Connectionless Server
  194. # o Concurrent, Connectionless Server
  195. # server repeatedly call "recvform" and let slave use "sendto"
  196. # to reply the client.
  197. # o concurrent, connection-oriented server algorithm
  198. # Master 1. Create a socket and bind to the well-known address
  199. # for the service being offered. Leave the socket unconnected
  200. # (socket,bind)
  201. # Master 2. Place the socket in passive mode, makeing it ready for used
  202. # by a server. (listen)
  203. # Master 3. Repeatedly call accept to receive the next request from
  204. # a client, and create a new slave process to handle the
  205. # response. (accept)
  206. # Slave 1. Receive a connection request (i.e., socket for the connection)
  207. # upon creation.
  208. # Slave 2. Interact with the client using the connection: read request(s)
  209. # and send back response(s).
  210. # Slave 3. Close the connection and exit. The slave process exits
  211. # after handling all requests from one client.
  212. #
  213. # Usage
  214. # &tcpinetserver([port-no,service-routine,before,each]);
  215. # for example
  216. # &tcpinetserver(1234,'simple_service');
  217. #
  218. $defaultserverport=1234;
  219. $defaultserviceroutine="simple_service";
  220. sub simple_service {
  221. local(*S)=@_;
  222. while (<S>) {
  223. if (/quit/) {
  224. return(0);
  225. } elsif (/help/) {
  226. print S <<"EOF";
  227. This is a simple sample server \r
  228. available command \r
  229. help quit \r
  230. EOF
  231. } else {
  232. print S "Unknown command\r\n";
  233. }
  234. }
  235. }
  236. sub reapchild {
  237. while (waitpid(-1,&WNOHANG|&WUNTRACED)>0) {
  238. # print "reapchild\n";
  239. # while (waitpid(-1,&WNOHANG)>0) {
  240. # print "reaping child\n";
  241. next;
  242. }
  243. 1;
  244. }
  245. #sub reapchild {
  246. # while (1) {
  247. # $pid = waitpid(-1,&WNOHANG);
  248. # last if ($pid < 1);
  249. # }
  250. #}
  251. sub dokill {
  252. kill 9,0;
  253. }
  254. sub main'tcpinetserver {
  255. local($port,$service,$before,$each)=@_;
  256. if ($port != 0) {
  257. $port = $defaultserverport unless $port;
  258. }
  259. $service = $defaultserviceroutine unless $service;
  260. local($sockaddr)= 'S n a4 x8';
  261. local($name,$aliases,$proto)=getprotobyname('tcp');
  262. local($name,$aliases,$port)=getservbyname($port,'tcp')
  263. unless $port =~ /^\d+$/;
  264. local(*S,*NS);
  265. chdir("/");
  266. socket(S, &PF_INET, &SOCK_STREAM, $proto) || die "socket: $!";
  267. setsockopt(S,main'SOL_SOCKET,main'SO_REUSEADDR,1);
  268. setsockopt(S,main'SOL_SOCKET,main'SO_LINGER,0);
  269. if ($port == 0) {
  270. local($hostname);
  271. chop($hostname = `hostname`);
  272. local($name, $aliases, $type, $len, $thisaddr) = gethostbyname($hostname);
  273. } else {
  274. $thisaddr = "\0\0\0\0";
  275. }
  276. $this = pack($sockaddr, &AF_INET, $port, $thisaddr);
  277. # can accept connection from $port, to any port in client
  278. bind(S, $this) || die "bind: $!";
  279. select(S); $| = 1; select(STDOUT);
  280. $SIG{'CHLD'} = 'reapchild';
  281. $SIG{'HUP'} = 'IGNORE';
  282. $SIG{'INT'} = 'dokill';
  283. $SIG{'TERM'} = 'dokill';
  284. do $before(S) if ($before);
  285. listen(S, 5) || die "connect: $!";
  286. for (;;) {
  287. # print "Listening again\n";
  288. ($addr = accept(NS,S)) || next;
  289. # || die "accept: $!\n";
  290. select(NS); $| = 1; select(STDOUT);
  291. # print "accept ok\n";
  292. ($af,$port,$inetaddr) = unpack($sockaddr,$addr);
  293. @inetaddr = unpack('C4',$inetaddr);
  294. # print "$af $port @inetaddr\n";
  295. FORK: {
  296. last if ( $pid = fork) ;
  297. if (defined $pid) {
  298. close(S);
  299. $return = do $service(NS);
  300. close(NS);
  301. exit($return);
  302. }
  303. if ($! =~ /No more process/) {
  304. sleep 5;
  305. redo FORK;
  306. } else {
  307. die "Can't fork: $!\n";
  308. }
  309. } # FORK
  310. do $each(NS) if ($each);
  311. close(NS);
  312. } # listen forever and fork a client to handle service request
  313. } # end tcpinetserver
  314. # single proecess, connection-oriented server for internet
  315. sub main'tcpinetsingleserver {
  316. local($port,$service,$beforeservice,$each)=@_;
  317. if ( $port != 0) {
  318. $port = $defaultserverport unless $port;
  319. }
  320. $service = $defaultserviceroutine unless $service;
  321. local($sockaddr)= 'S n a4 x8';
  322. local($name,$aliases,$proto)=getprotobyname('tcp');
  323. local($name,$aliases,$port)=getservbyname($port,'tcp')
  324. unless $port =~ /^\d+$/;
  325. local(*S,*NS);
  326. chdir("/");
  327. socket(S, &PF_INET, &SOCK_STREAM, $proto) || die "socket: $!";
  328. if ($port == 0) {
  329. local($hostname);
  330. chop($hostname = `hostname`);
  331. local($name, $aliases, $type, $len, $thisaddr) = gethostbyname($hostname);
  332. } else {
  333. $thisaddr = "\0\0\0\0";
  334. }
  335. $this = pack($sockaddr, &AF_INET, $port, $thisaddr);
  336. # can accept connection from $port, to any port in client
  337. bind(S, $this) || die "bind: $!";
  338. select(S); $| = 1; select(STDOUT);
  339. $SIG{'CHLD'} = 'reapchild';
  340. $SIG{'HUP'} = 'IGNORE';
  341. $SIG{'INT'} = 'dokill';
  342. do $beforeservice(S) if ($beforeservice);
  343. listen(S, 5) || die "connect: $!";
  344. for (;;) {
  345. # print "Listening again in single server\n";
  346. ($addr = accept(NS,S)) || next;
  347. select(NS); $| = 1; select(STDOUT);
  348. # print "accept ok\n";
  349. ($af,$port,$inetaddr) = unpack($sockaddr,$addr);
  350. @inetaddr = unpack('C4',$inetaddr);
  351. # print "$af $port @inetaddr\n";
  352. $return = do $service(NS);
  353. do $each(NS) if ($each);
  354. close(NS);
  355. }
  356. }
  357. # Concurrent, Connection-oriented server for UNIX domain
  358. $path=$defaultpath;
  359. sub doremove {
  360. unlink $path;
  361. kill 9,0;
  362. }
  363. sub simple_unixservice {
  364. local(*S)=@_;
  365. while (<S>) {
  366. if (/quit/) {
  367. return(0);
  368. } elsif (/help/) {
  369. print S <<"EOF";
  370. This is a simple sample server \r
  371. available command \r
  372. help quit \r
  373. EOF
  374. } else {
  375. print S "Unknown command\r\n";
  376. }
  377. }
  378. }
  379. sub main'tcpunixserver {
  380. ($path,$service)=@_;
  381. $path = $defaultpath unless $path;
  382. $service = 'simple_unixservice' unless $service;
  383. local($sockaddr)= 'S a14';
  384. socket(S, &PF_UNIX, &SOCK_STREAM, 0) || die "socket: $!";
  385. $this = pack($sockaddr, &AF_INET, $path);
  386. bind(S, $this) || die "bind: $!";
  387. select(S); $| = 1; select(STDOUT);
  388. $SIG{'CHLD'} = 'reapchild';
  389. $SIG{'HUP'} = 'IGNORE';
  390. $SIG{'INT'} = 'doremove';
  391. $SIG{'TERM'} = 'doremove';
  392. for (;;) {
  393. listen(S, 5) || die "connect: $!";
  394. # print "Listening again\n";
  395. ($addr = accept(NS,S)) || next;
  396. select(NS); $| = 1; select(STDOUT);
  397. # print "accept ok\n";
  398. FORK: {
  399. last if ( $pid = fork) ;
  400. if (defined $pid) {
  401. close(S);
  402. $return = do $service(NS);
  403. close(NS);
  404. exit($return);
  405. }
  406. if ($! =~ /No more process/) {
  407. sleep 5;
  408. redo FORK;
  409. } else {
  410. die "Can't fork: $!\n";
  411. }
  412. } # FORK
  413. close(NS);
  414. }
  415. }
  416. sub main'simpleunixclient {
  417. local($path)= @_;
  418. local(*S,$rin,$rout);
  419. ($path)= $defaultpath unless $path;
  420. &tcpunixclient(S,$path) || die "can't connect: $!\n";
  421. $rin='';
  422. vec($rin,fileno(STDIN),1)=1;
  423. vec($rin,fileno(S),1)=1;
  424. for (;;) {
  425. (($nf=select($rout=$rin,undef,undef,undef))>=0) || die "select: $!\n";
  426. if (vec($rout,fileno(S),1)) {
  427. $i=read(S,$n,1);
  428. if ($i) {
  429. print $n;
  430. } else {
  431. print "bye\n";
  432. last;
  433. }
  434. }
  435. if (vec($rout,fileno(STDIN),1)) {
  436. $_ = <STDIN>;
  437. chop;
  438. print S $_,"\r\n";
  439. }
  440. }
  441. }
  442. sub main'remotehostname {
  443. (*WNRP) = @_;
  444. local($there,$here)=(getpeername(WNRP),getsockname(WNRP));
  445. local($sockaddr)= 'S n a4 x8';
  446. local($family,$thisport,$thisaddr)=unpack($sockaddr,$here);
  447. local($family,$thatport,$thataddr)=unpack($sockaddr,$there);
  448. local(@localaddr)=unpack('C4',$thisaddr);
  449. local(@remoteaddr)=unpack('C4',$thataddr);
  450. local($hostname)=gethostbyaddr($thisaddr,&AF_INET);
  451. local($remotehostname)=gethostbyaddr($thataddr,&AF_INET);
  452. return ($remotehostname);
  453. }