1
0
mirror of https://github.com/golang/go synced 2024-11-22 02:04:40 -07:00

gc: better error messages for interface failures, conversions

x.go:13: cannot use t (type T) as type Reader in assignment:
	T does not implement Reader (Read method requires pointer receiver)
x.go:19: cannot use q (type Q) as type Reader in assignment:
	Q does not implement Reader (missing Read method)
		have read()
		want Read()
x.go:22: cannot use z (type int) as type Reader in assignment:
	int does not implement Reader (missing Read method)

x.go:24: too many arguments to conversion to complex: complex(1, 3)

R=ken2
CC=golang-dev
https://golang.org/cl/1736041
This commit is contained in:
Russ Cox 2010-06-20 11:45:53 -07:00
parent ceb868bf0a
commit a212d174ac
14 changed files with 139 additions and 58 deletions

View File

@ -645,7 +645,7 @@ genembedtramp(Type *rcvr, Type *method, Sym *newnam)
e = method->sym; e = method->sym;
for(d=0; d<nelem(dotlist); d++) { for(d=0; d<nelem(dotlist); d++) {
c = adddot1(e, rcvr, d, nil); c = adddot1(e, rcvr, d, nil, 0);
if(c == 1) if(c == 1)
goto out; goto out;
} }

View File

@ -645,7 +645,7 @@ genembedtramp(Type *rcvr, Type *method, Sym *newnam)
e = method->sym; e = method->sym;
for(d=0; d<nelem(dotlist); d++) { for(d=0; d<nelem(dotlist); d++) {
c = adddot1(e, rcvr, d, nil); c = adddot1(e, rcvr, d, nil, 0);
if(c == 1) if(c == 1)
goto out; goto out;
} }

View File

@ -651,7 +651,7 @@ genembedtramp(Type *rcvr, Type *method, Sym *newnam)
e = method->sym; e = method->sym;
for(d=0; d<nelem(dotlist); d++) { for(d=0; d<nelem(dotlist); d++) {
c = adddot1(e, rcvr, d, nil); c = adddot1(e, rcvr, d, nil, 0);
if(c == 1) if(c == 1)
goto out; goto out;
} }

View File

@ -1035,7 +1035,7 @@ int Tconv(Fmt *fp);
int Tpretty(Fmt *fp, Type *t); int Tpretty(Fmt *fp, Type *t);
int Zconv(Fmt *fp); int Zconv(Fmt *fp);
Node* adddot(Node *n); Node* adddot(Node *n);
int adddot1(Sym *s, Type *t, int d, Type **save); int adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase);
Type* aindex(Node *b, Type *t); Type* aindex(Node *b, Type *t);
int algtype(Type *t); int algtype(Type *t);
void argtype(Node *on, Type *t); void argtype(Node *on, Type *t);
@ -1066,7 +1066,7 @@ Type** getoutarg(Type *t);
Type* getoutargx(Type *t); Type* getoutargx(Type *t);
Type** getthis(Type *t); Type** getthis(Type *t);
Type* getthisx(Type *t); Type* getthisx(Type *t);
int implements(Type *t, Type *iface, Type **m, Type **samename); int implements(Type *t, Type *iface, Type **missing, Type **have, int *ptr);
void importdot(Pkg *opkg, Node *pack); void importdot(Pkg *opkg, Node *pack);
int is64(Type *t); int is64(Type *t);
int isblank(Node *n); int isblank(Node *n);

View File

@ -348,7 +348,10 @@ exprfmt(Fmt *f, Node *n, int prec)
fmtprint(f, "(%T)(", n->type); fmtprint(f, "(%T)(", n->type);
else else
fmtprint(f, "%T(", n->type); fmtprint(f, "%T(", n->type);
exprfmt(f, n->left, 0); if(n->left == N)
exprlistfmt(f, n->list);
else
exprfmt(f, n->left, 0);
fmtprint(f, ")"); fmtprint(f, ")");
break; break;

View File

@ -807,6 +807,7 @@ goopnames[] =
[OAS] = "=", [OAS] = "=",
[OAS2] = "=", [OAS2] = "=",
[OBREAK] = "break", [OBREAK] = "break",
[OCALL] = "function call",
[OCAP] = "cap", [OCAP] = "cap",
[OCASE] = "case", [OCASE] = "case",
[OCLOSED] = "closed", [OCLOSED] = "closed",
@ -1814,6 +1815,7 @@ int
assignop(Type *src, Type *dst, char **why) assignop(Type *src, Type *dst, char **why)
{ {
Type *missing, *have; Type *missing, *have;
int ptr;
if(why != nil) if(why != nil)
*why = ""; *why = "";
@ -1839,17 +1841,24 @@ assignop(Type *src, Type *dst, char **why)
// 3. dst is an interface type and src implements dst. // 3. dst is an interface type and src implements dst.
if(dst->etype == TINTER && src->etype != TNIL) { if(dst->etype == TINTER && src->etype != TNIL) {
if(implements(src, dst, &missing, &have)) if(implements(src, dst, &missing, &have, &ptr))
return OCONVIFACE; return OCONVIFACE;
if(why != nil) { if(why != nil) {
if(isptrto(src, TINTER)) if(isptrto(src, TINTER))
*why = smprint(": %T is pointer to interface, not interface", src); *why = smprint(":\n\t%T is pointer to interface, not interface", src);
else if(have && have->sym == missing->sym)
*why = smprint(":\n\t%T does not implement %T (wrong type for %S method)\n"
"\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
have->sym, have->type, missing->sym, missing->type);
else if(ptr)
*why = smprint(":\n\t%T does not implement %T (%S method requires pointer receiver)",
src, dst, missing->sym);
else if(have) else if(have)
*why = smprint(": %T does not implement %T (wrong type for %S method)\n" *why = smprint(":\n\t%T does not implement %T (missing %S method)\n"
"\thave %S%hhT\n\twant %S%hhT", src, dst, missing->sym, "\t\thave %S%hhT\n\t\twant %S%hhT", src, dst, missing->sym,
have->sym, have->type, missing->sym, missing->type); have->sym, have->type, missing->sym, missing->type);
else else
*why = smprint(": %T does not implement %T (missing %S method)", *why = smprint(":\n\t%T does not implement %T (missing %S method)",
src, dst, missing->sym); src, dst, missing->sym);
} }
return 0; return 0;
@ -2655,6 +2664,30 @@ setmaxarg(Type *t)
maxarg = w; maxarg = w;
} }
/* unicode-aware case-insensitive strcmp */
static int
cistrcmp(char *p, char *q)
{
Rune rp, rq;
while(*p || *q) {
if(*p == 0)
return +1;
if(*q == 0)
return -1;
p += chartorune(&rp, p);
q += chartorune(&rq, q);
rp = tolowerrune(rp);
rq = tolowerrune(rq);
if(rp < rq)
return -1;
if(rp > rq)
return +1;
}
return 0;
}
/* /*
* code to resolve elided DOTs * code to resolve elided DOTs
* in embedded types * in embedded types
@ -2664,7 +2697,7 @@ setmaxarg(Type *t)
// return count of fields+methods // return count of fields+methods
// found with a given name // found with a given name
static int static int
lookdot0(Sym *s, Type *t, Type **save) lookdot0(Sym *s, Type *t, Type **save, int ignorecase)
{ {
Type *f, *u; Type *f, *u;
int c; int c;
@ -2676,7 +2709,7 @@ lookdot0(Sym *s, Type *t, Type **save)
c = 0; c = 0;
if(u->etype == TSTRUCT || u->etype == TINTER) { if(u->etype == TSTRUCT || u->etype == TINTER) {
for(f=u->type; f!=T; f=f->down) for(f=u->type; f!=T; f=f->down)
if(f->sym == s) { if(f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0)) {
if(save) if(save)
*save = f; *save = f;
c++; c++;
@ -2685,7 +2718,7 @@ lookdot0(Sym *s, Type *t, Type **save)
u = methtype(t); u = methtype(t);
if(u != T) { if(u != T) {
for(f=u->method; f!=T; f=f->down) for(f=u->method; f!=T; f=f->down)
if(f->sym == s && f->embedded == 0) { if(f->embedded == 0 && (f->sym == s || (ignorecase && cistrcmp(f->sym->name, s->name) == 0))) {
if(save) if(save)
*save = f; *save = f;
c++; c++;
@ -2700,7 +2733,7 @@ lookdot0(Sym *s, Type *t, Type **save)
// answer is in dotlist array and // answer is in dotlist array and
// count of number of ways is returned. // count of number of ways is returned.
int int
adddot1(Sym *s, Type *t, int d, Type **save) adddot1(Sym *s, Type *t, int d, Type **save, int ignorecase)
{ {
Type *f, *u; Type *f, *u;
int c, a; int c, a;
@ -2710,7 +2743,7 @@ adddot1(Sym *s, Type *t, int d, Type **save)
t->trecur = 1; t->trecur = 1;
if(d == 0) { if(d == 0) {
c = lookdot0(s, t, save); c = lookdot0(s, t, save, ignorecase);
goto out; goto out;
} }
@ -2727,7 +2760,7 @@ adddot1(Sym *s, Type *t, int d, Type **save)
continue; continue;
if(f->sym == S) if(f->sym == S)
continue; continue;
a = adddot1(s, f->type, d, save); a = adddot1(s, f->type, d, save, ignorecase);
if(a != 0 && c == 0) if(a != 0 && c == 0)
dotlist[d].field = f; dotlist[d].field = f;
c += a; c += a;
@ -2764,7 +2797,7 @@ adddot(Node *n)
goto ret; goto ret;
for(d=0; d<nelem(dotlist); d++) { for(d=0; d<nelem(dotlist); d++) {
c = adddot1(s, t, d, nil); c = adddot1(s, t, d, nil, 0);
if(c > 0) if(c > 0)
goto out; goto out;
} }
@ -2902,7 +2935,7 @@ expandmeth(Sym *s, Type *t)
for(sl=slist; sl!=nil; sl=sl->link) { for(sl=slist; sl!=nil; sl=sl->link) {
sl->field->sym->flags &= ~SymUniq; sl->field->sym->flags &= ~SymUniq;
for(d=0; d<nelem(dotlist); d++) { for(d=0; d<nelem(dotlist); d++) {
c = adddot1(sl->field->sym, t, d, &f); c = adddot1(sl->field->sym, t, d, &f, 0);
if(c == 0) if(c == 0)
continue; continue;
if(c == 1) { if(c == 1) {
@ -3035,7 +3068,7 @@ genwrapper(Type *rcvr, Type *method, Sym *newnam)
} }
static Type* static Type*
ifacelookdot(Sym *s, Type *t, int *followptr) ifacelookdot(Sym *s, Type *t, int *followptr, int ignorecase)
{ {
int i, c, d; int i, c, d;
Type *m; Type *m;
@ -3046,7 +3079,7 @@ ifacelookdot(Sym *s, Type *t, int *followptr)
return T; return T;
for(d=0; d<nelem(dotlist); d++) { for(d=0; d<nelem(dotlist); d++) {
c = adddot1(s, t, d, &m); c = adddot1(s, t, d, &m, ignorecase);
if(c > 1) { if(c > 1) {
yyerror("%T.%S is ambiguous", t, s); yyerror("%T.%S is ambiguous", t, s);
return T; return T;
@ -3069,7 +3102,7 @@ ifacelookdot(Sym *s, Type *t, int *followptr)
} }
int int
implements(Type *t, Type *iface, Type **m, Type **samename) implements(Type *t, Type *iface, Type **m, Type **samename, int *ptr)
{ {
Type *t0, *im, *tm, *rcvr, *imtype; Type *t0, *im, *tm, *rcvr, *imtype;
int followptr; int followptr;
@ -3090,11 +3123,13 @@ implements(Type *t, Type *iface, Type **m, Type **samename)
goto found; goto found;
*m = im; *m = im;
*samename = tm; *samename = tm;
*ptr = 0;
return 0; return 0;
} }
} }
*m = im; *m = im;
*samename = nil; *samename = nil;
*ptr = 0;
return 0; return 0;
found:; found:;
} }
@ -3106,10 +3141,14 @@ implements(Type *t, Type *iface, Type **m, Type **samename)
expandmeth(t->sym, t); expandmeth(t->sym, t);
for(im=iface->type; im; im=im->down) { for(im=iface->type; im; im=im->down) {
imtype = methodfunc(im->type, 0); imtype = methodfunc(im->type, 0);
tm = ifacelookdot(im->sym, t, &followptr); tm = ifacelookdot(im->sym, t, &followptr, 0);
if(tm == T || !eqtype(methodfunc(tm->type, 0), imtype)) { if(tm == T || !eqtype(methodfunc(tm->type, 0), imtype)) {
print("try case\n");
if(tm == T)
tm = ifacelookdot(im->sym, t, &followptr, 1);
*m = im; *m = im;
*samename = tm; *samename = tm;
*ptr = 0;
return 0; return 0;
} }
// if pointer receiver in method, // if pointer receiver in method,
@ -3120,6 +3159,7 @@ implements(Type *t, Type *iface, Type **m, Type **samename)
yyerror("interface pointer mismatch"); yyerror("interface pointer mismatch");
*m = im; *m = im;
*samename = nil; *samename = nil;
*ptr = 1;
return 0; return 0;
} }
} }

View File

@ -14,7 +14,7 @@
#include "go.h" #include "go.h"
static void implicitstar(Node**); static void implicitstar(Node**);
static int onearg(Node*); static int onearg(Node*, char*, ...);
static int twoarg(Node*); static int twoarg(Node*);
static int lookdot(Node*, Type*, int); static int lookdot(Node*, Type*, int);
static void typecheckaste(int, Type*, NodeList*, char*); static void typecheckaste(int, Type*, NodeList*, char*);
@ -63,7 +63,7 @@ typechecklist(NodeList *l, int top)
Node* Node*
typecheck(Node **np, int top) typecheck(Node **np, int top)
{ {
int et, op; int et, op, ptr;
Node *n, *l, *r; Node *n, *l, *r;
NodeList *args; NodeList *args;
int lno, ok, ntop; int lno, ok, ntop;
@ -532,7 +532,7 @@ reswitch:
goto error; goto error;
} }
if(n->type != T && n->type->etype != TINTER) if(n->type != T && n->type->etype != TINTER)
if(!implements(n->type, t, &missing, &have)) { if(!implements(n->type, t, &missing, &have, &ptr)) {
if(have) if(have)
yyerror("impossible type assertion: %+N cannot have dynamic type %T" yyerror("impossible type assertion: %+N cannot have dynamic type %T"
" (wrong type for %S method)\n\thave %S%hhT\n\twant %S%hhT", " (wrong type for %S method)\n\thave %S%hhT\n\twant %S%hhT",
@ -710,10 +710,10 @@ reswitch:
ok |= Erv; ok |= Erv;
// turn CALL(type, arg) into CONV(arg) w/ type // turn CALL(type, arg) into CONV(arg) w/ type
n->left = N; n->left = N;
if(onearg(n) < 0)
goto error;
n->op = OCONV; n->op = OCONV;
n->type = l->type; n->type = l->type;
if(onearg(n, "conversion to %T", l->type) < 0)
goto error;
goto doconv; goto doconv;
} }
@ -770,7 +770,7 @@ reswitch:
case OREAL: case OREAL:
case OIMAG: case OIMAG:
ok |= Erv; ok |= Erv;
if(onearg(n) < 0) if(onearg(n, "%#O", n->op) < 0)
goto error; goto error;
typecheck(&n->left, Erv); typecheck(&n->left, Erv);
defaultlit(&n->left, T); defaultlit(&n->left, T);
@ -850,7 +850,7 @@ reswitch:
case OCLOSED: case OCLOSED:
case OCLOSE: case OCLOSE:
if(onearg(n) < 0) if(onearg(n, "%#O", n->op) < 0)
goto error; goto error;
typecheck(&n->left, Erv); typecheck(&n->left, Erv);
defaultlit(&n->left, T); defaultlit(&n->left, T);
@ -1053,7 +1053,7 @@ reswitch:
case OPANIC: case OPANIC:
ok |= Etop; ok |= Etop;
if(onearg(n) < 0) if(onearg(n, "panic") < 0)
goto error; goto error;
typecheck(&n->left, Erv); typecheck(&n->left, Erv);
defaultlit(&n->left, T); defaultlit(&n->left, T);
@ -1273,20 +1273,30 @@ implicitstar(Node **nn)
} }
static int static int
onearg(Node *n) onearg(Node *n, char *f, ...)
{ {
va_list arg;
char *p;
if(n->left != N) if(n->left != N)
return 0; return 0;
if(n->list == nil) { if(n->list == nil) {
yyerror("missing argument to %#O - %#N", n->op, n); va_start(arg, f);
p = vsmprint(f, arg);
va_end(arg);
yyerror("missing argument to %s: %#N", p, n);
return -1; return -1;
} }
n->left = n->list->n;
if(n->list->next != nil) { if(n->list->next != nil) {
yyerror("too many arguments to %#O", n->op); va_start(arg, f);
p = vsmprint(f, arg);
va_end(arg);
yyerror("too many arguments to %s: %#N", p, n);
n->left = n->list->n;
n->list = nil; n->list = nil;
return -1; return -1;
} }
n->left = n->list->n;
n->list = nil; n->list = nil;
return 0; return 0;
} }
@ -1307,7 +1317,7 @@ twoarg(Node *n)
return -1; return -1;
} }
if(n->list->next->next != nil) { if(n->list->next->next != nil) {
yyerror("too many arguments to %#O", n->op); yyerror("too many arguments to %#O - %#N", n->op, n);
n->list = nil; n->list = nil;
return -1; return -1;
} }

View File

@ -724,10 +724,8 @@ sub RunWeb {
"firefox", "firefox",
); );
foreach my $b (@alt) { foreach my $b (@alt) {
if (-f $b) { if (system($b, $fname) == 0) {
if (system($b, $fname) == 0) { return;
return;
}
} }
} }

View File

@ -14,6 +14,7 @@ import (
"image" "image"
"io" "io"
"os" "os"
"strconv"
) )
// Color type, as per the PNG spec. // Color type, as per the PNG spec.
@ -108,7 +109,7 @@ func (d *decoder) parseIHDR(r io.Reader, crc hash.Hash32, length uint32) os.Erro
} }
crc.Write(d.tmp[0:13]) crc.Write(d.tmp[0:13])
if d.tmp[8] != 8 { if d.tmp[8] != 8 {
return UnsupportedError("bit depth") return UnsupportedError("bit depth " + strconv.Itoa(int(d.tmp[8])))
} }
if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 { if d.tmp[10] != 0 || d.tmp[11] != 0 || d.tmp[12] != 0 {
return UnsupportedError("compression, filter or interlace method") return UnsupportedError("compression, filter or interlace method")

View File

@ -93,7 +93,13 @@ func (client *Client) input() {
c := client.pending[seq] c := client.pending[seq]
client.pending[seq] = c, false client.pending[seq] = c, false
client.mutex.Unlock() client.mutex.Unlock()
if c == nil {
err = os.NewError("invalid response sequence number")
break
}
err = client.codec.ReadResponseBody(c.Reply) err = client.codec.ReadResponseBody(c.Reply)
// TODO(rsc): Should look at err, but breaks tests.
// Empty strings should turn into nil os.Errors // Empty strings should turn into nil os.Errors
if response.Error != "" { if response.Error != "" {
c.Error = os.ErrorString(response.Error) c.Error = os.ErrorString(response.Error)

View File

@ -58,7 +58,8 @@ func TestServer(t *testing.T) {
cli, srv := net.Pipe() cli, srv := net.Pipe()
defer cli.Close() defer cli.Close()
go ServeConn(srv) var ci rpc.ClientInfo
go ServeConn(srv, &ci)
dec := json.NewDecoder(cli) dec := json.NewDecoder(cli)
// Send hand-coded requests to server, parse responses. // Send hand-coded requests to server, parse responses.
@ -84,8 +85,9 @@ func TestServer(t *testing.T) {
func TestClient(t *testing.T) { func TestClient(t *testing.T) {
// Assume server is okay (TestServer is above). // Assume server is okay (TestServer is above).
// Test client against server. // Test client against server.
var ci rpc.ClientInfo
cli, srv := net.Pipe() cli, srv := net.Pipe()
go ServeConn(srv) go ServeConn(srv, &ci)
client := NewClient(cli) client := NewClient(cli)
defer client.Close() defer client.Close()

View File

@ -118,6 +118,6 @@ func (c *serverCodec) Close() os.Error {
// ServeConn runs the JSON-RPC server on a single connection. // ServeConn runs the JSON-RPC server on a single connection.
// ServeConn blocks, serving the connection until the client hangs up. // ServeConn blocks, serving the connection until the client hangs up.
// The caller typically invokes ServeConn in a go statement. // The caller typically invokes ServeConn in a go statement.
func ServeConn(conn io.ReadWriteCloser) { func ServeConn(conn io.ReadWriteCloser, ci *rpc.ClientInfo) {
rpc.ServeCodec(NewServerCodec(conn)) rpc.ServeCodec(NewServerCodec(conn), ci)
} }

View File

@ -158,6 +158,12 @@ type Response struct {
Error string // error, if any. Error string // error, if any.
} }
// ClientInfo records information about an RPC client connection.
type ClientInfo struct {
LocalAddr string
RemoteAddr string
}
type serverType struct { type serverType struct {
sync.Mutex // protects the serviceMap sync.Mutex // protects the serviceMap
serviceMap map[string]*service serviceMap map[string]*service
@ -208,7 +214,7 @@ func (server *serverType) register(rcvr interface{}) os.Error {
} }
// Method needs three ins: receiver, *args, *reply. // Method needs three ins: receiver, *args, *reply.
// The args and reply must be structs until gobs are more general. // The args and reply must be structs until gobs are more general.
if mtype.NumIn() != 3 { if mtype.NumIn() != 3 && mtype.NumIn() != 4 {
log.Stderr("method", mname, "has wrong number of ins:", mtype.NumIn()) log.Stderr("method", mname, "has wrong number of ins:", mtype.NumIn())
continue continue
} }
@ -238,6 +244,13 @@ func (server *serverType) register(rcvr interface{}) os.Error {
log.Stderr(mname, "reply type not public:", replyType) log.Stderr(mname, "reply type not public:", replyType)
continue continue
} }
if mtype.NumIn() == 4 {
t := mtype.In(3)
if t != reflect.Typeof((*ClientInfo)(nil)) {
log.Stderr(mname, "last argument not *ClientInfo")
continue
}
}
// Method needs one out: os.Error. // Method needs one out: os.Error.
if mtype.NumOut() != 1 { if mtype.NumOut() != 1 {
log.Stderr("method", mname, "has wrong number of outs:", mtype.NumOut()) log.Stderr("method", mname, "has wrong number of outs:", mtype.NumOut())
@ -288,13 +301,19 @@ func sendResponse(sending *sync.Mutex, req *Request, reply interface{}, codec Se
sending.Unlock() sending.Unlock()
} }
func (s *service) call(sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec) { func (s *service) call(sending *sync.Mutex, mtype *methodType, req *Request, argv, replyv reflect.Value, codec ServerCodec, ci *ClientInfo) {
mtype.Lock() mtype.Lock()
mtype.numCalls++ mtype.numCalls++
mtype.Unlock() mtype.Unlock()
function := mtype.method.Func function := mtype.method.Func
// Invoke the method, providing a new value for the reply. // Invoke the method, providing a new value for the reply.
returnValues := function.Call([]reflect.Value{s.rcvr, argv, replyv}) var args []reflect.Value
if mtype.method.Type.NumIn() == 3 {
args = []reflect.Value{s.rcvr, argv, replyv}
} else {
args = []reflect.Value{s.rcvr, argv, replyv, reflect.NewValue(ci)}
}
returnValues := function.Call(args)
// The return value for the method is an os.Error. // The return value for the method is an os.Error.
errInter := returnValues[0].Interface() errInter := returnValues[0].Interface()
errmsg := "" errmsg := ""
@ -329,7 +348,7 @@ func (c *gobServerCodec) Close() os.Error {
return c.rwc.Close() return c.rwc.Close()
} }
func (server *serverType) input(codec ServerCodec) { func (server *serverType) input(codec ServerCodec, ci *ClientInfo) {
sending := new(sync.Mutex) sending := new(sync.Mutex)
for { for {
// Grab the request header. // Grab the request header.
@ -376,7 +395,7 @@ func (server *serverType) input(codec ServerCodec) {
sendResponse(sending, req, replyv.Interface(), codec, err.String()) sendResponse(sending, req, replyv.Interface(), codec, err.String())
break break
} }
go service.call(sending, mtype, req, argv, replyv, codec) go service.call(sending, mtype, req, argv, replyv, codec, ci)
} }
codec.Close() codec.Close()
} }
@ -387,7 +406,7 @@ func (server *serverType) accept(lis net.Listener) {
if err != nil { if err != nil {
log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit? log.Exit("rpc.Serve: accept:", err.String()) // TODO(r): exit?
} }
go ServeConn(conn) go ServeConn(conn, &ClientInfo{conn.LocalAddr().String(), conn.RemoteAddr().String()})
} }
} }
@ -419,14 +438,14 @@ type ServerCodec interface {
// The caller typically invokes ServeConn in a go statement. // The caller typically invokes ServeConn in a go statement.
// ServeConn uses the gob wire format (see package gob) on the // ServeConn uses the gob wire format (see package gob) on the
// connection. To use an alternate codec, use ServeCodec. // connection. To use an alternate codec, use ServeCodec.
func ServeConn(conn io.ReadWriteCloser) { func ServeConn(conn io.ReadWriteCloser, ci *ClientInfo) {
ServeCodec(&gobServerCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(conn)}) ServeCodec(&gobServerCodec{conn, gob.NewDecoder(conn), gob.NewEncoder(conn)}, ci)
} }
// ServeCodec is like ServeConn but uses the specified codec to // ServeCodec is like ServeConn but uses the specified codec to
// decode requests and encode responses. // decode requests and encode responses.
func ServeCodec(codec ServerCodec) { func ServeCodec(codec ServerCodec, ci *ClientInfo) {
server.input(codec) server.input(codec, ci)
} }
// Accept accepts connections on the listener and serves requests // Accept accepts connections on the listener and serves requests
@ -452,7 +471,11 @@ func serveHTTP(c *http.Conn, req *http.Request) {
return return
} }
io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n") io.WriteString(conn, "HTTP/1.0 "+connected+"\n\n")
ServeConn(conn) ci := &ClientInfo{
LocalAddr: conn.(net.Conn).LocalAddr().String(),
RemoteAddr: c.RemoteAddr,
}
ServeConn(conn, ci)
} }
// HandleHTTP registers an HTTP handler for RPC messages. // HandleHTTP registers an HTTP handler for RPC messages.

View File

@ -48,7 +48,6 @@
# ./gc.go # ./gc.go
# ./gc1.go # ./gc1.go
./hashmap.go ./hashmap.go
./hilbert.go
./helloworld.go ./helloworld.go
./if.go ./if.go
./if1.go ./if1.go
@ -332,7 +331,6 @@ fixedbugs/bug149.go
fixedbugs/bug150.go fixedbugs/bug150.go
fixedbugs/bug151.go fixedbugs/bug151.go
fixedbugs/bug152.go fixedbugs/bug152.go
fixedbugs/bug153.go
# fixedbugs/bug154.go # needs floating point # fixedbugs/bug154.go # needs floating point
fixedbugs/bug155.go fixedbugs/bug155.go
fixedbugs/bug156.go fixedbugs/bug156.go