diff options
Diffstat (limited to 'ext')
-rw-r--r-- | ext/MANIFEST | 6 | ||||
-rw-r--r-- | ext/Makefile.in | 40 | ||||
-rw-r--r-- | ext/dbm.c | 441 | ||||
-rw-r--r-- | ext/dbm.doc | 107 | ||||
-rw-r--r-- | ext/socket.c | 761 | ||||
-rw-r--r-- | ext/socket.doc | 227 |
6 files changed, 1582 insertions, 0 deletions
diff --git a/ext/MANIFEST b/ext/MANIFEST new file mode 100644 index 0000000000..881a97c39e --- /dev/null +++ b/ext/MANIFEST @@ -0,0 +1,6 @@ +MANIFEST +Makefile.in +dbm.c +dbm.doc +socket.c +socket.doc diff --git a/ext/Makefile.in b/ext/Makefile.in new file mode 100644 index 0000000000..20d8c5c9c4 --- /dev/null +++ b/ext/Makefile.in @@ -0,0 +1,40 @@ +2SHELL = /bin/sh + +#### Start of system configuration section. #### + +srcdir = @srcdir@ +VPATH = @srcdir@ + +CC = @CC@ + +CFLAGS = -I.. @CCDLFLAGS@ @CFLAGS@ +LIBS = @LIBS@ +EXT = @EXT@ + +prefix = @prefix@ +binprefix = +exec_prefix = @exec_prefix@ +bindir = $(exec_prefix)/bin + +#### End of system configuration section. #### + +.SUFFIXES: .so $(SUFFIXES) + +OBJS = dbm.$(EXT) \ + socket.$(EXT) + +all: $(OBJS) + +clean:; @rm -f *.o *.so + +realclean:; @rm -f *.o *.so + @rm -f core ruby *~ Makefile + +.o.so: + ld -o $*.so $*.o + +# Prevent GNU make v3 from overflowing arg limit on SysV. +.NOEXPORT: +### +dbm.o: dbm.c ../ruby.h ../config.h ../defines.h +socket.o: socket.c ../ruby.h ../config.h ../defines.h ../io.h diff --git a/ext/dbm.c b/ext/dbm.c new file mode 100644 index 0000000000..f3e8295d6a --- /dev/null +++ b/ext/dbm.c @@ -0,0 +1,441 @@ +/************************************************ + + dbm.c - + + $Author: matz $ + $Date: 1995/01/10 10:42:24 $ + created at: Mon Jan 24 15:59:52 JST 1994 + + Copyright (C) 1995 Yukihiro Matsumoto + +************************************************/ + +#include "ruby.h" + +#ifdef USE_DBM + +#include <ndbm.h> +#include <fcntl.h> +#include <errno.h> + +VALUE C_DBM; +static ID id_dbm; + +extern VALUE M_Enumerable; + +static void +closeddbm() +{ + Fail("closed DBM file"); +} + +#define GetDBM(obj, dbmp) {\ + DBM **_dbm;\ + Get_Data_Struct(obj, id_dbm, DBM*, _dbm);\ + dbmp = *_dbm;\ + if (dbmp == Qnil) closeddbm();\ +} + +static void +free_dbm(dbmp) + DBM **dbmp; +{ + if (*dbmp) dbm_close(*dbmp); +} + +#define MakeDBM(obj, dp) {\ + DBM **_dbm;\ + if (!id_dbm) id_dbm = rb_intern("dbm");\ + Make_Data_Struct(obj,id_dbm,DBM*,Qnil,free_dbm,_dbm);\ + *_dbm=dp;\ +} + +static VALUE +Sdbm_open(argc, argv, class) + int argc; + VALUE *argv; + VALUE class; +{ + VALUE file, vmode; + DBM *dbm, **dbm2; + int mode; + VALUE obj; + + if (rb_scan_args(argc, argv, "11", &file, &vmode) == 1) { + mode = 0666; /* default value */ + } + else if (NIL_P(vmode)) { + mode = -1; /* return nil if DB not exist */ + } + else { + mode = NUM2INT(vmode); + } + Check_Type(file, T_STRING); + + dbm = Qnil; + if (mode >= 0) + dbm = dbm_open(RSTRING(file)->ptr, O_RDWR|O_CREAT, mode); + if (!dbm) + dbm = dbm_open(RSTRING(file)->ptr, O_RDWR, mode); + if (!dbm) + dbm = dbm_open(RSTRING(file)->ptr, O_RDONLY, mode); + + if (!dbm) { + if (mode == -1) return Qnil; + rb_sys_fail(RSTRING(file)->ptr); + } + + obj = obj_alloc(class); + MakeDBM(obj, dbm); + + return obj; +} + +static VALUE +Fdbm_close(obj) + VALUE obj; +{ + DBM **dbmp; + + Get_Data_Struct(obj, id_dbm, DBM*, dbmp); + if (*dbmp == Qnil) Fail("already closed DBM file"); + dbm_close(*dbmp); + *dbmp = Qnil; + + return Qnil; +} + +static VALUE +Fdbm_fetch(obj, keystr) + VALUE obj, keystr; +{ + datum key, value; + DBM *dbm; + + Check_Type(keystr, T_STRING); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + + GetDBM(obj, dbm); + value = dbm_fetch(dbm, key); + if (value.dptr == Qnil) { + return Qnil; + } + return str_new(value.dptr, value.dsize); +} + +static VALUE +Fdbm_indexes(obj, args) + VALUE obj; + struct RArray *args; +{ + VALUE *p, *pend; + struct RArray *new; + int i = 0; + + if (!args || args->len == 1 && TYPE(args->ptr) != T_ARRAY) { + args = (struct RArray*)rb_to_a(args->ptr[0]); + } + + new = (struct RArray*)ary_new2(args->len); + + p = args->ptr; pend = p + args->len; + while (p < pend) { + new->ptr[i++] = Fdbm_fetch(obj, *p++); + new->len = i; + } + return (VALUE)new; +} + +static VALUE +Fdbm_delete(obj, keystr) + VALUE obj, keystr; +{ + datum key; + DBM *dbm; + + Check_Type(keystr, T_STRING); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + + GetDBM(obj, dbm); + if (dbm_delete(dbm, key)) { + Fail("dbm_delete failed"); + } + return obj; +} + +static VALUE +Fdbm_shift(obj) + VALUE obj; +{ + datum key, val; + DBM *dbm; + VALUE keystr, valstr; + + GetDBM(obj, dbm); + + key = dbm_firstkey(dbm); + if (!key.dptr) return Qnil; + val = dbm_fetch(dbm, key); + dbm_delete(dbm, key); + + keystr = str_new(key.dptr, key.dsize); + valstr = str_new(val.dptr, val.dsize); + return assoc_new(keystr, valstr); +} + +static VALUE +Fdbm_delete_if(obj) + VALUE obj; +{ + datum key, val; + DBM *dbm; + VALUE keystr, valstr; + + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + keystr = str_new(key.dptr, key.dsize); + valstr = str_new(val.dptr, val.dsize); + if (rb_yield(assoc_new(keystr, valstr)) + && dbm_delete(dbm, key)) { + Fail("dbm_delete failed"); + } + } + return obj; +} + +static VALUE +Fdbm_clear(obj) + VALUE obj; +{ + datum key; + DBM *dbm; + + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + if (dbm_delete(dbm, key)) { + Fail("dbm_delete failed"); + } + } + return obj; +} + +static VALUE +Fdbm_store(obj, keystr, valstr) + VALUE obj, keystr, valstr; +{ + datum key, val; + DBM *dbm; + + if (valstr == Qnil) { + Fdbm_delete(obj, keystr); + return Qnil; + } + + Check_Type(keystr, T_STRING); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + Check_Type(valstr, T_STRING); + val.dptr = RSTRING(valstr)->ptr; + val.dsize = RSTRING(valstr)->len; + + GetDBM(obj, dbm); + if (dbm_store(dbm, key, val, DBM_REPLACE)) { + dbm_clearerr(dbm); + if (errno == EPERM) rb_sys_fail(Qnil); + Fail("dbm_store failed"); + } + return valstr; +} + +static VALUE +Fdbm_length(obj) + VALUE obj; +{ + datum key; + DBM *dbm; + int i = 0; + + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + i++; + } + return INT2FIX(i); +} + +static VALUE +Fdbm_each_value(obj) + VALUE obj; +{ + datum key, val; + DBM *dbm; + + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + rb_yield(str_new(val.dptr, val.dsize)); + } + return obj; +} + +static VALUE +Fdbm_each_key(obj) + VALUE obj; +{ + datum key; + DBM *dbm; + + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + rb_yield(str_new(key.dptr, key.dsize)); + } + return obj; +} + +static VALUE +Fdbm_each_pair(obj) + VALUE obj; +{ + datum key, val; + DBM *dbm; + VALUE keystr, valstr; + + GetDBM(obj, dbm); + + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + keystr = str_new(key.dptr, key.dsize); + valstr = str_new(val.dptr, val.dsize); + rb_yield(assoc_new(keystr, valstr)); + } + + return obj; +} + +static VALUE +Fdbm_keys(obj) + VALUE obj; +{ + datum key; + DBM *dbm; + VALUE ary; + + ary = ary_new(); + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + ary_push(ary, str_new(key.dptr, key.dsize)); + } + + return ary; +} + +static VALUE +Fdbm_values(obj) + VALUE obj; +{ + datum key, val; + DBM *dbm; + VALUE ary; + + ary = ary_new(); + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + ary_push(ary, str_new(val.dptr, val.dsize)); + } + + return ary; +} + +static VALUE +Fdbm_has_key(obj, keystr) + VALUE obj, keystr; +{ + datum key, val; + DBM *dbm; + + Check_Type(keystr, T_STRING); + key.dptr = RSTRING(keystr)->ptr; + key.dsize = RSTRING(keystr)->len; + + GetDBM(obj, dbm); + val = dbm_fetch(dbm, key); + if (val.dptr) return TRUE; + return FALSE; +} + +static VALUE +Fdbm_has_value(obj, valstr) + VALUE obj, valstr; +{ + datum key, val; + DBM *dbm; + + Check_Type(valstr, T_STRING); + val.dptr = RSTRING(valstr)->ptr; + val.dsize = RSTRING(valstr)->len; + + GetDBM(obj, dbm); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + if (val.dsize == RSTRING(valstr)->len && + memcmp(val.dptr, RSTRING(valstr)->ptr, val.dsize) == 0) + return TRUE; + } + return FALSE; +} + +static VALUE +Fdbm_to_a(obj) + VALUE obj; +{ + datum key, val; + DBM *dbm; + VALUE ary; + + GetDBM(obj, dbm); + + ary = ary_new(); + for (key = dbm_firstkey(dbm); key.dptr; key = dbm_nextkey(dbm)) { + val = dbm_fetch(dbm, key); + ary_push(ary, assoc_new(str_new(key.dptr, key.dsize), + str_new(val.dptr, val.dsize))); + } + + return ary; +} + +Init_dbm() +{ +#ifdef HAVE_LIBDBM + dln_load_lib("libdbm.a"); +#endif + C_DBM = rb_define_class("DBM", C_Object); + rb_include_module(C_DBM, M_Enumerable); + + rb_define_single_method(C_DBM, "open", Sdbm_open, -1); + rb_define_method(C_DBM, "close", Fdbm_close, 0); + rb_define_method(C_DBM, "[]", Fdbm_fetch, 1); + rb_define_method(C_DBM, "[]=", Fdbm_store, 2); + rb_define_method(C_DBM, "indexes", Fdbm_indexes, -2); + rb_define_method(C_DBM, "length", Fdbm_length, 0); + rb_define_alias(C_DBM, "size", "length"); + rb_define_method(C_DBM, "each", Fdbm_each_pair, 0); + rb_define_method(C_DBM, "each_value", Fdbm_each_value, 0); + rb_define_method(C_DBM, "each_key", Fdbm_each_key, 0); + rb_define_method(C_DBM, "each_pair", Fdbm_each_pair, 0); + rb_define_method(C_DBM, "keys", Fdbm_keys, 0); + rb_define_method(C_DBM, "values", Fdbm_values, 0); + rb_define_method(C_DBM, "shift", Fdbm_shift, 1); + rb_define_method(C_DBM, "delete", Fdbm_delete, 1); + rb_define_method(C_DBM, "delete_if", Fdbm_delete_if, 0); + rb_define_method(C_DBM, "clear", Fdbm_clear, 0); + rb_define_method(C_DBM, "includes", Fdbm_has_key, 1); + rb_define_method(C_DBM, "has_key", Fdbm_has_key, 1); + rb_define_method(C_DBM, "has_value", Fdbm_has_value, 1); + + rb_define_method(C_DBM, "to_a", Fdbm_to_a, 0); +} +#endif /* USE_DBM */ diff --git a/ext/dbm.doc b/ext/dbm.doc new file mode 100644 index 0000000000..48c91a9157 --- /dev/null +++ b/ext/dbm.doc @@ -0,0 +1,107 @@ +.\" dbm.doc - -*- Indented-Text -*- created at: Thu Mar 23 20:28:31 JST 1995 + +** DBM(クラス) + +NDBMファイルをアクセスするクラス.キー,データともに文字列でなければな +らないという制限と,データがファイルに保存されるという点を除いては +Dictクラスと全く同様に扱うことができる.NDBMを備えていないシステムでは +このクラスは定義されない. + +SuperClass: Object + +Included Modules: Enumerable + +Methods: + + self [key] + + keyをキーとする値を返す. + + self [key]= value + + keyをキーとして,valueを格納する.valueとしてnilを指定すると, + keyに対する項目の削除となる. + + clear + + DBMファイルの中身を空にする. + + close + + DBMファイルをクローズする.以後の操作は例外を発生させる. + + delete(key) + + keyをキーとする組を削除する. + + delete_if + + 要素を削除するイテレータ.key::valueというペアを与えて,ブロッ + クを評価した値が真の時,該当する項目を削除する. + + each + each_pair + + key::valueなるペアを与えるイテレータ. + + each_key + + 全てのkeyに対して繰り返すイテレータ. + + each_value + + 全てのvalueに対して繰り返すイテレータ. + + has_key(key) + includes(key) + + keyがデータベース中に存在する時,真を返す + + has_value(value) + + valueを値とする組がデータベース中に存在する時,真を + 返す + + indexes(ary) + indexes(key-1, ..., key-n) + + 1番目の形式では文字列の配列を引数として受けて,その要素をキー + とする要素を含む配列を返す.2番目の形式では各引数の値をキーと + する要素を含む配列を返す. + + keys + + データベース中に存在するキー全てを含む配列を返す. + + length + size + + データベース中の要素の数を返す.(注意:現在の実現では要素数を数 + えるためにデータベースを全部検索するので,結構コストが高い.気 + をつけて使うこと.) + + shift + + データベース中の要素をを一つ取り出し(データベースから削除する), + key::valueというペアを返す. + + to_a + + データベース中のkey-valueペアを要素とする配列を返す. + + values + + データベース中に存在する値全てを含む配列を返す. + +Single Methods: + + open(dbname[, mode]) + + dbnameで指定したデータベースをモードをmodeに設定してオープンす + る.modeの省略値は0666である.modeとしてnilを指定するとデータ + ベースが既に存在しない時には新たにオープンせず,nilを返す. + +------------------------------------------------------- +Local variables: +fill-column: 70 +end: diff --git a/ext/socket.c b/ext/socket.c new file mode 100644 index 0000000000..ec992340a4 --- /dev/null +++ b/ext/socket.c @@ -0,0 +1,761 @@ +/************************************************ + + socket.c - + + $Author: matz $ + $Date: 1995/01/10 10:42:55 $ + created at: Thu Mar 31 12:21:29 JST 1994 + +************************************************/ + +#include "ruby.h" +#ifdef HAVE_SOCKET +#include "io.h" +#include <stdio.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <errno.h> +#include <sys/un.h> + +extern VALUE C_IO; +VALUE C_BasicSocket; +VALUE C_TCPsocket; +VALUE C_TCPserver; +VALUE C_UNIXsocket; +VALUE C_UNIXserver; +VALUE C_Socket; + +FILE *rb_fdopen(); +char *strdup(); + +static VALUE +sock_new(class, fd) + VALUE class; + int fd; +{ + VALUE sock = obj_alloc(class); + OpenFile *fp; + + MakeOpenFile(sock, fp); + fp->f = rb_fdopen(fd, "r"); + setbuf(fp->f, NULL); + fp->f2 = rb_fdopen(fd, "w"); + fp->mode = FMODE_READWRITE|FMODE_SYNC; + + return sock; +} + +static VALUE +Fbsock_shutdown(argc, argv, sock) + int argc; + VALUE *argv; + VALUE sock; +{ + VALUE howto; + int how; + OpenFile *fptr; + + rb_scan_args(argc, argv, "01", &howto); + if (howto == Qnil) + how = 2; + else { + how = NUM2INT(howto); + if (how < 0 && how > 2) how = 2; + } + GetOpenFile(sock, fptr); + if (shutdown(fileno(fptr->f), how) == -1) + rb_sys_fail(Qnil); + + return INT2FIX(0); +} + +static VALUE +Fbsock_setopt(sock, lev, optname, val) + VALUE sock, lev, optname; + struct RString *val; +{ + int level, option; + OpenFile *fptr; + + level = NUM2INT(lev); + option = NUM2INT(optname); + Check_Type(val, T_STRING); + + GetOpenFile(sock, fptr); + if (setsockopt(fileno(fptr->f), level, option, val->ptr, val->len) < 0) + rb_sys_fail(fptr->path); + + return INT2FIX(0); +} + +static VALUE +Fbsock_getopt(sock, lev, optname) + VALUE sock, lev, optname; +{ + int level, option, len; + struct RString *val; + OpenFile *fptr; + + level = NUM2INT(lev); + option = NUM2INT(optname); + len = 256; + val = (struct RString*)str_new(0, len); + Check_Type(val, T_STRING); + + GetOpenFile(sock, fptr); + if (getsockopt(fileno(fptr->f), level, option, val->ptr, &len) < 0) + rb_sys_fail(fptr->path); + val->len = len; + return (VALUE)val; +} + +static VALUE +Fbsock_getsockname(sock) + VALUE sock; +{ + char buf[1024]; + int len = sizeof buf; + OpenFile *fptr; + + GetOpenFile(sock, fptr); + if (getsockname(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0) + rb_sys_fail("getsockname(2)"); + return str_new(buf, len); +} + +static VALUE +Fbsock_getpeername(sock) + VALUE sock; +{ + char buf[1024]; + int len = sizeof buf; + OpenFile *fptr; + + GetOpenFile(sock, fptr); + if (getpeername(fileno(fptr->f), (struct sockaddr*)buf, &len) < 0) + rb_sys_fail("getpeername(2)"); + return str_new(buf, len); +} + +static VALUE +open_inet(class, h, serv, server) + VALUE class, h, serv; + int server; +{ + char *host; + struct hostent *hostent, _hostent; + struct servent *servent, _servent; + struct protoent *protoent; + struct sockaddr_in sockaddr; + int fd, status; + int hostaddr, hostaddrPtr[2]; + int servport; + char *syscall; + VALUE sock; + + if (h) { + Check_Type(h, T_STRING); + host = RSTRING(h)->ptr; + hostent = gethostbyname(host); + if (hostent == NULL) { + hostaddr = inet_addr(host); + if (hostaddr == -1) { + if (server && !strlen(host)) + hostaddr = INADDR_ANY; + else + rb_sys_fail(host); + } + _hostent.h_addr_list = (char **)hostaddrPtr; + _hostent.h_addr_list[0] = (char *)&hostaddr; + _hostent.h_addr_list[1] = NULL; + _hostent.h_length = sizeof(hostaddr); + _hostent.h_addrtype = AF_INET; + hostent = &_hostent; + } + } + servent = NULL; + if (FIXNUM_P(serv)) { + servport = FIX2UINT(serv); + goto setup_servent; + } + Check_Type(serv, T_STRING); + servent = getservbyname(RSTRING(serv)->ptr, "tcp"); + if (servent == NULL) { + servport = strtoul(RSTRING(serv)->ptr, Qnil, 0); + if (servport == -1) Fail("no such servce %s", RSTRING(serv)->ptr); + setup_servent: + _servent.s_port = servport; + _servent.s_proto = "tcp"; + servent = &_servent; + } + protoent = getprotobyname(servent->s_proto); + if (protoent == NULL) Fail("no such proto %s", servent->s_proto); + + fd = socket(PF_INET, SOCK_STREAM, protoent->p_proto); + + sockaddr.sin_family = AF_INET; + if (h == Qnil) { + sockaddr.sin_addr.s_addr = INADDR_ANY; + } + else { + memcpy((char *)&(sockaddr.sin_addr.s_addr), + (char *) hostent->h_addr_list[0], + (size_t) hostent->h_length); + } + sockaddr.sin_port = servent->s_port; + + if (server) { + status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + syscall = "bind(2)"; + } + else { + status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + syscall = "connect(2)"; + } + + if (status < 0) { + close (fd); + rb_sys_fail(syscall); + } + if (server) listen(fd, 5); + + /* create new instance */ + sock = sock_new(class, fd); + + return sock; +} + +static VALUE +Stcp_sock_open(class, host, serv) + VALUE class, host, serv; +{ + Check_Type(host, T_STRING); + return open_inet(class, host, serv, 0); +} + +static VALUE +Stcp_svr_open(argc, argv, class) + int argc; + VALUE *argv; + VALUE class; +{ + VALUE arg1, arg2; + + if (rb_scan_args(argc, argv, "11", &arg1, &arg2) == 2) + return open_inet(class, arg1, arg2, 1); + else + return open_inet(class, Qnil, arg1, 1); +} + +static VALUE +sock_accept(class, fd, sockaddr, len) + VALUE class; + int fd; + struct sockaddr *sockaddr; + int *len; +{ + int fd2; + + retry: + fd2 = accept(fd, sockaddr, len); + if (fd2 < 0) { + if (errno == EINTR) goto retry; + rb_sys_fail(Qnil); + } + return sock_new(class, fd2); +} + +static VALUE +Ftcp_accept(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_in from; + int fromlen; + + GetOpenFile(sock, fptr); + fromlen = sizeof(struct sockaddr_in); + return sock_accept(C_TCPsocket, fileno(fptr->f), + (struct sockaddr*)&from, &fromlen); +} + +static VALUE +open_unix(class, path, server) + VALUE class; + struct RString *path; + int server; +{ + struct sockaddr_un sockaddr; + int fd, status; + char *syscall; + VALUE sock; + OpenFile *fptr; + + Check_Type(path, T_STRING); + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) rb_sys_fail("socket(2)"); + + sockaddr.sun_family = AF_UNIX; + strncpy(sockaddr.sun_path, path->ptr, sizeof(sockaddr.sun_path)-1); + sockaddr.sun_path[sizeof(sockaddr.sun_path)-1] = '\0'; + + if (server) { + status = bind(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + syscall = "bind(2)"; + } + else { + status = connect(fd, (struct sockaddr*)&sockaddr, sizeof(sockaddr)); + syscall = "connect(2)"; + } + + if (status < 0) { + close (fd); + rb_sys_fail(syscall); + } + + if (server) listen(fd, 5); + + sock = sock_new(class, fd); + GetOpenFile(sock, fptr); + fptr->path = strdup(path->ptr); + + return sock; +} + +static VALUE +tcp_addr(sockaddr) + struct sockaddr_in *sockaddr; +{ + VALUE family, port, addr; + VALUE ary; + struct hostent *hostent; + + family = str_new2("AF_INET"); + hostent = gethostbyaddr((char*)&sockaddr->sin_addr.s_addr, + sizeof(sockaddr->sin_addr), + AF_INET); + if (hostent) { + addr = str_new2(hostent->h_name); + } + else { + char buf[16]; + char *a = (char*)&sockaddr->sin_addr; + sprintf(buf, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]); + addr = str_new2(buf); + } + port = INT2FIX(sockaddr->sin_port); + ary = ary_new3(3, family, port, addr); + + return ary; +} + +static VALUE +Ftcp_addr(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_in addr; + int len = sizeof addr; + + GetOpenFile(sock, fptr); + + if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail("getsockname(2)"); + return tcp_addr(&addr); +} + +static VALUE +Ftcp_peeraddr(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_in addr; + int len = sizeof addr; + + GetOpenFile(sock, fptr); + + if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail("getsockname(2)"); + return tcp_addr(&addr); +} + +static VALUE +Sunix_sock_open(sock, path) + VALUE sock, path; +{ + return open_unix(sock, path, 0); +} + +static VALUE +Funix_path(sock) + VALUE sock; +{ + OpenFile *fptr; + + GetOpenFile(sock, fptr); + if (fptr->path == Qnil) { + struct sockaddr_un addr; + int len = sizeof(addr); + if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail(Qnil); + fptr->path = strdup(addr.sun_path); + } + return str_new2(fptr->path); +} + +static VALUE +Sunix_svr_open(class, path) + VALUE class, path; +{ + return open_unix(class, path, 1); +} + +static VALUE +Funix_accept(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_un from; + int fromlen; + + GetOpenFile(sock, fptr); + fromlen = sizeof(struct sockaddr_un); + return sock_accept(C_UNIXsocket, fileno(fptr->f), + (struct sockaddr*)&from, &fromlen); +} + +static VALUE +unix_addr(sockaddr) + struct sockaddr_un *sockaddr; +{ + return assoc_new(str_new2("AF_UNIX"),str_new2(sockaddr->sun_path)); +} + +static VALUE +Funix_addr(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_un addr; + int len = sizeof addr; + + GetOpenFile(sock, fptr); + + if (getsockname(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail("getsockname(2)"); + return unix_addr(&addr); +} + +static VALUE +Funix_peeraddr(sock) + VALUE sock; +{ + OpenFile *fptr; + struct sockaddr_un addr; + int len = sizeof addr; + + GetOpenFile(sock, fptr); + + if (getpeername(fileno(fptr->f), (struct sockaddr*)&addr, &len) < 0) + rb_sys_fail("getsockname(2)"); + return unix_addr(&addr); +} + +static void +setup_domain_and_type(domain, dv, type, tv) + VALUE domain, type; + int *dv, *tv; +{ + char *ptr; + + if (TYPE(domain) == T_STRING) { + ptr = RSTRING(domain)->ptr; + if (strcmp(ptr, "PF_UNIX") == 0) + *dv = PF_UNIX; + else if (strcmp(ptr, "PF_INET") == 0) + *dv = PF_INET; +#ifdef PF_IMPLINK + else if (strcmp(ptr, "PF_IMPLINK") == 0) + *dv = PF_IMPLINK; +#endif +#ifdef PF_AX25 + else if (strcmp(ptr, "PF_AX25") == 0) + *dv = PF_AX25; +#endif +#ifdef PF_IPX + else if (strcmp(ptr, "PF_IPX") == 0) + *dv = PF_IPX; +#endif + else + Fail("Unknown socket domain %s", ptr); + } + else { + *dv = NUM2INT(domain); + } + if (TYPE(type) == T_STRING) { + ptr = RSTRING(type)->ptr; + if (strcmp(ptr, "SOCK_STREAM") == 0) + *tv = SOCK_STREAM; + else if (strcmp(ptr, "SOCK_DGRAM") == 0) + *tv = SOCK_DGRAM; +#ifdef SOCK_RAW + else if (strcmp(ptr, "SOCK_RAW") == 0) + *tv = SOCK_RAW; +#endif +#ifdef SOCK_SEQPACKET + else if (strcmp(ptr, "SOCK_SEQPACKET") == 0) + *tv = SOCK_SEQPACKET; +#endif +#ifdef SOCK_RDM + else if (strcmp(ptr, "SOCK_RDM") == 0) + *tv = SOCK_RDM; +#endif +#ifdef SOCK_PACKET + else if (strcmp(ptr, "SOCK_PACKET") == 0) + *tv = SOCK_PACKET; +#endif + else + Fail("Unknown socket type %s", ptr); + } + else { + *tv = NUM2INT(type); + } +} + +static VALUE +Ssock_open(class, domain, type, protocol) + VALUE class, domain, type, protocol; +{ + int fd; + int d, t; + + setup_domain_and_type(domain, &d, type, &t); + fd = socket(d, t, NUM2INT(protocol)); + if (fd < 0) rb_sys_fail("socke(2)"); + return sock_new(class, fd); +} + +static VALUE +Ssock_for_fd(class, fd) + VALUE class, fd; +{ + return sock_new(class, NUM2INT(fd)); +} + +static VALUE +Ssock_socketpair(class, domain, type, protocol) + VALUE class, domain, type, protocol; +{ + int fd; + int d, t, sp[2]; + + setup_domain_and_type(domain, &d, type, &t); + if (socketpair(d, t, NUM2INT(protocol), sp) < 0) + rb_sys_fail("socketpair(2)"); + + return assoc_new(sock_new(class, sp[0]), sock_new(class, sp[1])); +} + +static VALUE +Fsock_connect(sock, addr) + VALUE sock; + struct RString *addr; +{ + OpenFile *fptr; + + Check_Type(addr, T_STRING); + str_modify(addr); + + GetOpenFile(sock, fptr); + if (connect(fileno(fptr->f), (struct sockaddr*)addr->ptr, addr->len) < 0) + rb_sys_fail("connect(2)"); + + return INT2FIX(0); +} + +static VALUE +Fsock_bind(sock, addr) + VALUE sock; + struct RString *addr; +{ + OpenFile *fptr; + + Check_Type(addr, T_STRING); + str_modify(addr); + + GetOpenFile(sock, fptr); + if (bind(fileno(fptr->f), (struct sockaddr*)addr->ptr, addr->len) < 0) + rb_sys_fail("bind(2)"); + + return INT2FIX(0); +} + +static VALUE +Fsock_listen(sock, log) + VALUE sock, log; +{ + OpenFile *fptr; + + GetOpenFile(sock, fptr); + if (listen(fileno(fptr->f), NUM2INT(log)) < 0) + rb_sys_fail("listen(2)"); + + return INT2FIX(0); +} + +static VALUE +Fsock_accept(sock) + VALUE sock; +{ + OpenFile *fptr; + VALUE addr, sock2; + char buf[1024]; + int len = sizeof buf; + + GetOpenFile(sock, fptr); + sock2 = sock_accept(C_Socket,fileno(fptr->f),(struct sockaddr*)buf,&len); + + return assoc_new(sock2, str_new(buf, len)); +} + +static VALUE +Fsock_send(argc, argv, sock) + int argc; + VALUE *argv; + VALUE sock; +{ + struct RString *msg, *to; + VALUE flags; + OpenFile *fptr; + FILE *f; + int fd, n; + + rb_scan_args(argc, argv, "21", &msg, &flags, &to); + + Check_Type(msg, T_STRING); + + GetOpenFile(sock, fptr); + f = fptr->f2?fptr->f2:fptr->f; + fd = fileno(f); + if (to) { + Check_Type(to, T_STRING); + n = sendto(fd, msg->ptr, msg->len, NUM2INT(flags), + (struct sockaddr*)to->ptr, to->len); + } + else { + n = send(fd, msg->ptr, msg->len, NUM2INT(flags)); + } + if (n < 0) { + rb_sys_fail("send(2)"); + } + return INT2FIX(n); +} + +static VALUE +sock_recv(sock, argc, argv, from) + VALUE sock; + int argc; + VALUE *argv; + int from; +{ + OpenFile *fptr; + FILE f; + struct RString *str; + char buf[1024]; + int fd, alen = sizeof buf; + VALUE len, flg; + int flags; + + rb_scan_args(argc, argv, "11", &len, &flg); + + if (flg == Qnil) flags = 0; + else flags = NUM2INT(flg); + + str = (struct RString*)str_new(0, NUM2INT(len)); + + GetOpenFile(sock, fptr); + fd = fileno(fptr->f); + if ((str->len = recvfrom(fd, str->ptr, str->len, flags, + (struct sockaddr*)buf, &alen)) < 0) { + rb_sys_fail("recvfrom(2)"); + } + + if (from) + return assoc_new(str, str_new(buf, alen)); + else + return (VALUE)str; +} + +static VALUE +Fsock_recv(argc, argv, sock) + int argc; + VALUE *argv; + VALUE sock; +{ + return sock_recv(sock, argc, argv, 0); +} + +static VALUE +Fsock_recvfrom(argc, argv, sock) + int argc; + VALUE *argv; + VALUE sock; +{ + return sock_recv(sock, argc, argv, 1); +} + +Init_socket () +{ +#ifdef HAVE_LIBSOCKET + dln_load_lib("libsocket.a"); +#endif + C_BasicSocket = rb_define_class("BasicSocket", C_IO); + rb_undef_method(C_BasicSocket, "new"); + rb_define_method(C_BasicSocket, "shutdown", Fbsock_shutdown, -1); + rb_define_method(C_BasicSocket, "setopt", Fbsock_setopt, 3); + rb_define_method(C_BasicSocket, "getopt", Fbsock_getopt, 2); + rb_define_method(C_BasicSocket, "getsockname", Fbsock_getsockname, 0); + rb_define_method(C_BasicSocket, "getpeername", Fbsock_getpeername, 0); + + C_TCPsocket = rb_define_class("TCPsocket", C_BasicSocket); + rb_define_single_method(C_TCPsocket, "open", Stcp_sock_open, 2); + rb_define_single_method(C_TCPsocket, "new", Stcp_sock_open, 2); + rb_define_method(C_TCPsocket, "addr", Ftcp_addr, 0); + rb_define_method(C_TCPsocket, "peeraddr", Ftcp_peeraddr, 0); + + C_TCPserver = rb_define_class("TCPserver", C_TCPsocket); + rb_define_single_method(C_TCPserver, "open", Stcp_svr_open, -1); + rb_define_single_method(C_TCPserver, "new", Stcp_svr_open, -1); + rb_define_method(C_TCPserver, "accept", Ftcp_accept, 0); + + C_UNIXsocket = rb_define_class("UNIXsocket", C_BasicSocket); + rb_define_single_method(C_UNIXsocket, "open", Sunix_sock_open, 1); + rb_define_single_method(C_UNIXsocket, "new", Sunix_sock_open, 1); + rb_define_method(C_UNIXsocket, "path", Funix_path, 0); + rb_define_method(C_UNIXsocket, "addr", Funix_addr, 0); + rb_define_method(C_UNIXsocket, "peeraddr", Funix_peeraddr, 0); + + C_UNIXserver = rb_define_class("UNIXserver", C_UNIXsocket); + rb_define_single_method(C_UNIXserver, "open", Sunix_svr_open, 1); + rb_define_single_method(C_UNIXserver, "new", Sunix_svr_open, 1); + rb_define_method(C_UNIXserver, "accept", Funix_accept, 0); + + C_Socket = rb_define_class("Socket", C_BasicSocket); + rb_define_single_method(C_Socket, "open", Ssock_open, 3); + rb_define_single_method(C_Socket, "new", Ssock_open, 3); + rb_define_single_method(C_Socket, "for_fd", Ssock_for_fd, 1); + + rb_define_method(C_Socket, "connect", Fsock_connect, 1); + rb_define_method(C_Socket, "bind", Fsock_bind, 1); + rb_define_method(C_Socket, "listen", Fsock_listen, 1); + rb_define_method(C_Socket, "accept", Fsock_accept, 0); + + rb_define_method(C_Socket, "send", Fsock_send, -1); + rb_define_method(C_Socket, "recv", Fsock_recv, -1); + rb_define_method(C_Socket, "recvfrom", Fsock_recv, -1); + + rb_define_single_method(C_Socket, "socketpair", Ssock_socketpair, 3); +} +#endif /* HAVE_SOCKET */ diff --git a/ext/socket.doc b/ext/socket.doc new file mode 100644 index 0000000000..aa5bfedbff --- /dev/null +++ b/ext/socket.doc @@ -0,0 +1,227 @@ +.\" socket.doc - -*- Indented-Text -*- created at: Thu Mar 23 20:29:02 JST 1995 + +** Socket(クラス) + +SuperClass: BasicSocket + +ソケットそのものに対するシステムコールレベルのアクセスを提供するクラス. +Perlのソケットに対するアクセスと同レベルの機能を提供している.このクラ +スではソケットアドレスはpackされた文字列で,指定する.UDPソケットはこ +のクラスを使って利用する. + +Methods: + + accept + + 新しい接続を受け付けて,新しい接続に対するソケットとアドレスの + ペアを返す.accept(2)を参照. + + bind(addr) + + bind(2)と同じ働きをする.addrはpackされたソケットアドレス構造 + 体である. + + connect(addr) + + connect(2)と同じ働きをする.addrはpackされたソケットアドレス構 + 造体である. + + listen(backlog) + + listen(2)と同じ働きをする. + + recv(len[, flags]) + + ソケットからデータを受け取り,文字列として返す.lenは受け取る + 最大の長さを指定する.flagsについてはrecv(2)を参照.flagsのデ + フォルト値は0である. + + recvfrom(len[, flags]) + + recvと同様にソケットからデータを受け取るが,戻り値は文字列と相 + 手ソケットのアドレスのペアである.引数についてはrecvと同様. + + send(mesg, flags[, to]) + + ソケットを介してデータを送る.flagsに関してはsend(2)を参照の事. + connectしていないソケットに対しては送り先であるtoを指定する必 + 要がある.実際に送ったデータの長さを返す. + +Single Methods: + + open(domain, type, protocol) + new(domain, type, protocol) + + 新しいソケットを生成する.domain,type,protocolはインクルード + ファイルで定義されている定数値で指定する.domainとtypeに関して + は,文字列で指定できるが,すべてをカバーしている保証はない. + + socketpair(domain, type, protocol) + + ソケットのペアを返す.引数の指定は openと同じである. + +** BasicSocket(クラス) + +ソケットを表す抽象クラス.具体的なソケット操作はサブクラスで定義される. +例えばインターネットドメインの場合はTCPsocketを用いる. + +SuperClass: IO + +Methods: + + getopt(level, optname) + + ソケットのオプションを取得する.getsockopt(2)を参照のこと.取 + 得したオプションの内容を含む文字列を返す. + + getpeername + + 接続の相手先のソケットの情報を得る.パックされたsockaddr構造体 + をベタにダンプした文字列が返される.getpeername(2)を参照のこと. + + getsockname + + ソケットの情報を得る.パックされたsockaddr構造体をベタにダンプ + した文字列が返される.getsockname(2)を参照のこと. + + setopt(level, optname, optval) + + ソケットのオプションを設定する.setsockopt(2)を参照のこと. + + shutdown(how) + + ソケットの以降の接続を終了させる.howが0である時,以降の受信が, + howが1である時は,以降の送信が拒否される.howが2の時には,それ + 以降の送信,受信ともに拒否される.shutdown(2)を参照. + +** TCPserver(クラス) + +TCP/IPストリーム型接続のサーバ側のソケットのクラス.このクラスによって +簡単にソケットを利用したサーバのプログラミングができる.例えばechoサー +バは以下のようになる. + + gs = TCPserver.open(4444) + socks = [gs] + + while TRUE + nsock = select(socks); + if nsock == nil; continue end + for s in nsock[0] + if s == gs + socks.push(s.accept) + else + if s.eof + s.close + socks.delete(s) + else + str = s.gets + s.write(str) + end + end + end + end + +SuperClass: TCPsocket + +Methods: + + accept + + クライアントからの接続要求を受け付け,接続したTCPsocketのイン + スタンスを返す. + +Single Methods: + + new([host, ]service) + open([host, ]service) + + serviceは/etc/services(またはNIS)に登録されているサービス名か + ポート番号で指定する.hostを指定した時は指定したホストからの接 + 続だけを受け付ける.省略時は全てのホストからの接続要求を受け付 + ける. + +** TCPsocket + +インターネットドメインのストリーム型ソケットのクラス.通常のIOクラスの +サブクラスと同様の入出力ができる.このクラスによってソケットを用いたク +ライアントを簡単に記述できる.ユーザの入力をそのままサーバに転送するプ +ログラムは以下のようになる. + + s = TCPsocket("localhost", 4444) + while gets() + s.write($_) + print(s.read) + end + +SuperClass: BasicSocket + +Methods: + + addr + + ソケットの接続情報を表す配列を返す.その配列の各要素は第1要素 + が文字列 "AF_INET",第2要素がport番号,第3要素がホストを表す文 + 字列である. + + peeraddr + + 接続相手先ソケットの情報を表す配列を返す.その配列の各要素は + addrメソッドが返す配列と同じである. + +Single Methods: + + open(host, service) + new(host, service) + + hostで指定したホストのserviceで指定したポートと接続したソケッ + トを返す.hostはホスト名,またはインターネットアドレスを示す文 + 字列,serviceは/etc/services(またはNIS)に登録されているサービ + ス名かポート番号である. + +** UNIXserver + +UNIXストリーム型接続のサーバ側のソケットのクラス. + +SuperClass: UNIXsocket + +Methods: + + accept + + クライアントからの接続要求を受け付け,接続したUNIXsocketのイン + スタンスを返す. + +** UNIXsocket + +UNIXドメインのストリーム型ソケットのクラス.通常のIOクラスのサブクラス +と同様の入出力ができる. + +SuperClass: BasicSocket + +Methods: + + addr + + ソケットの接続情報を表す配列を返す.その配列の各要素は第1要素 + が文字列 "AF_UNIX",第2要素がpathである. + + path + + UNIXソケットのパスを返す. + + peeraddr + + 接続相手先ソケットの情報を表す配列を返す.その配列の各要素は + addrメソッドが返す配列と同じである. + +Single Methods: + + open(path) + new(path) + + pathで指定したパス名を用いて接続したソケットを返す. + +------------------------------------------------------- +Local variables: +fill-column: 70 +end: |