5 * ddd.ddd.ddd.ddd,nnnn IPv4 address and port
6 * ... host or port may be `*'
7 * /abs/path/to/socket AF_UNIX
8 * ./rel/path/to/socket AF_UNIX
14 #define SOCKADDR_LEN(sa) ((sa)->end - (sa)->begin)
18 int pat_sockaddr(Tcl_Interp *ip, Tcl_Obj *o, SockAddr_Value *val) {
21 rc= Tcl_ConvertToType(ip,o,&sockaddr_type);
24 *val= *OBJ_SOCKADDR(o);
28 Tcl_Obj *ret_sockaddr(Tcl_Interp *ip, SockAddr_Value val) {
32 Tcl_InvalidateStringRep(o);
33 *OBJ_SOCKADDR(o)= val;
34 o->typePtr= &sockaddr_type;
38 /* native type methods */
40 void sockaddr_clear(SockAddr_Value *v) { v->begin= v->end= 0; }
42 void sockaddr_create(SockAddr_Value *v, const struct sockaddr *addr, int len) {
45 v->begin= begin= TALLOC(len);
46 memcpy(begin, addr, len);
50 int sockaddr_len(const SockAddr_Value *v) {
51 return SOCKADDR_LEN(v);
54 const struct sockaddr *sockaddr_addr(const SockAddr_Value *v) {
55 return (const void*)v->begin;
58 void sockaddr_free(const SockAddr_Value *v) {
62 /* Sockaddr Tcl type */
64 static void sockaddr_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
66 sockaddr_create(OBJ_SOCKADDR(dup),
67 sockaddr_addr(OBJ_SOCKADDR(src)),
68 sockaddr_len(OBJ_SOCKADDR(src)));
71 static void sockaddr_t_free(Tcl_Obj *o) {
72 sockaddr_free(OBJ_SOCKADDR(o));
75 static void sockaddr_t_ustr(Tcl_Obj *o) {
76 const struct sockaddr *sa;
77 char i46buf[INET6_ADDRSTRLEN];
79 const char *string, *prepend;
81 sa= sockaddr_addr(OBJ_SOCKADDR(o));
82 al= sockaddr_len(OBJ_SOCKADDR(o));
84 switch (sa->sa_family) {
87 assert(sizeof(i46buf) >= INET_ADDRSTRLEN);
88 assert(al >= sizeof(struct sockaddr_in));
89 inet_ntop(sa->sa_family, sa, i46buf, al);
95 assert(al >= sizeof(struct sockaddr_un));
96 string= ((const struct sockaddr_un*)sa)->sun_path;
98 if (!string[0]) string="//";
99 else if (string[0] != '/' || string[1] == '/') prepend= "./";
101 default: /* ouch ! */
102 obj_updatestr_array_prefix(o,(const void*)sa,al,"?");
108 o->bytes= TALLOC(sl+1);
109 memcpy(o->bytes, prepend, pl);
110 memcpy(o->bytes+pl, string, sl+1);
113 static int sockaddr_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
115 struct sockaddr_un sun;
116 struct sockaddr_in sin;
118 unsigned long port_l;
120 char *str, *ep, *copy;
122 const char *comma, *path;
124 str= Tcl_GetStringFromObj(o,0); assert(str);
126 memset(&s,0,sizeof(s));
128 if (str[0]=='/' || (str[0]=='.' && str[1]=='/')) {
131 s.sun.sun_family= AF_UNIX;
133 if (strcmp(str,"//")) path= "";
134 else if (memcmp(str,"./",2) && str[2]) path= str+2;
135 else { assert(str[0]=='/' && str[1]!='/'); path=str; }
137 if (strlen(str) >= sizeof(s.sun.sun_path))
138 return staticerr(ip, "AF_UNIX path too long");
140 strcpy(s.sun.sun_path, str);
142 } else if ((comma= strchr(str, ','))) {
145 s.sin.sin_family= AF_INET;
149 memcpy(copy, str, pl);
152 if (!strcmp(copy,"*")) {
153 s.sin.sin_addr.s_addr= INADDR_ANY;
156 iprv= inet_pton(AF_INET, copy, &s.sin.sin_addr);
160 if (!iprv) return staticerr(ip, "bad IPv4 address syntax");
163 if (!strcmp(comma,"*")) {
166 errno=0; port_l=strtoul(comma,&ep,10);
167 if (errno || *ep) return staticerr(ip, "bad IPv4 port");
168 if (port_l > 65535) return staticerr(ip, "IPv4 port out of range");
169 s.sin.sin_port= htons(port_l);
174 return staticerr(ip, "bad socket address syntax");
178 sockaddr_create(OBJ_SOCKADDR(o), (void*)&s, sl);
180 o->typePtr = &sockaddr_type;
184 Tcl_ObjType sockaddr_type = {
186 sockaddr_t_free, sockaddr_t_dup, sockaddr_t_ustr, sockaddr_t_sfa