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
13 #define SOCKADDR_LEN(sa) ((sa)->end - (sa)->begin)
17 int cht_pat_sockaddr(Tcl_Interp *ip, Tcl_Obj *o, SockAddr_Value *val) {
20 rc= Tcl_ConvertToType(ip,o,&sockaddr_type);
23 *val= *OBJ_SOCKADDR(o);
27 Tcl_Obj *cht_ret_sockaddr(Tcl_Interp *ip, SockAddr_Value val) {
31 Tcl_InvalidateStringRep(o);
32 *OBJ_SOCKADDR(o)= val;
33 o->typePtr= &sockaddr_type;
37 /* native type methods */
39 void cht_sockaddr_clear(SockAddr_Value *v) { v->begin= v->end= 0; }
41 void cht_sockaddr_create(SockAddr_Value *v, const struct sockaddr *a, int al) {
44 v->begin= begin= TALLOC(al);
49 int cht_sockaddr_len(const SockAddr_Value *v) {
50 return SOCKADDR_LEN(v);
53 const struct sockaddr *cht_sockaddr_addr(const SockAddr_Value *v) {
54 return (const void*)v->begin;
57 void cht_sockaddr_free(const SockAddr_Value *v) {
61 /* Sockaddr Tcl type */
63 static void sockaddr_t_dup(Tcl_Obj *src, Tcl_Obj *dup) {
64 cht_sockaddr_create(OBJ_SOCKADDR(dup),
65 cht_sockaddr_addr(OBJ_SOCKADDR(src)),
66 cht_sockaddr_len(OBJ_SOCKADDR(src)));
67 dup->typePtr= &cht_hbytes_type;
70 static void sockaddr_t_free(Tcl_Obj *o) {
71 cht_sockaddr_free(OBJ_SOCKADDR(o));
74 static void sockaddr_t_ustr(Tcl_Obj *o) {
75 const struct sockaddr *sa;
76 char i46buf[INET6_ADDRSTRLEN], portbuf[50];
77 const struct sockaddr_in *sin;
79 const char *string, *prepend;
81 sa= cht_sockaddr_addr(OBJ_SOCKADDR(o));
82 al= cht_sockaddr_len(OBJ_SOCKADDR(o));
84 switch (sa->sa_family) {
87 assert(sizeof(i46buf) >= INET_ADDRSTRLEN);
88 assert(al >= sizeof(struct sockaddr_in));
90 inet_ntop(sa->sa_family, &sin->sin_addr, i46buf, al);
91 snprintf(portbuf,sizeof(portbuf),",%d",(int)ntohs(sin->sin_port));
97 string= ((const struct sockaddr_un*)sa)->sun_path;
99 if (!string[0]) string="//";
100 else if (string[0] != '/' || string[1] == '/') prepend= "./";
103 default: /* ouch ! */
104 cht_obj_updatestr_array_prefix(o,(const void*)sa,al,"?");
108 cht_obj_updatestr_vstringls(o,
109 prepend, strlen(prepend),
110 string, strlen(string),
114 static int sockaddr_t_sfa(Tcl_Interp *ip, Tcl_Obj *o) {
116 struct sockaddr_un sun;
117 struct sockaddr_in sin;
119 unsigned long port_l;
121 char *str, *ep, *copy;
123 const char *comma, *path;
125 str= Tcl_GetStringFromObj(o,0); assert(str);
127 memset(&s,0,sizeof(s));
129 if (str[0]=='/' || (str[0]=='.' && str[1]=='/')) {
132 s.sun.sun_family= AF_UNIX;
134 if (!strcmp(str,"//")) path= "";
135 else if (!memcmp(str,"./",2) && str[2]) path= str+2;
136 else { assert(str[0]=='/' && str[1]!='/'); path=str; }
138 if (strlen(str) >= sizeof(s.sun.sun_path))
139 return cht_staticerr(ip, "AF_UNIX path too long", "SOCKADDR AFUNIX LENGTH");
141 strcpy(s.sun.sun_path, path);
143 } else if ((comma= strchr(str, ','))) {
146 s.sin.sin_family= AF_INET;
150 memcpy(copy, str, pl);
153 if (!strcmp(copy,"*")) {
154 s.sin.sin_addr.s_addr= INADDR_ANY;
157 iprv= inet_pton(AF_INET, copy, &s.sin.sin_addr);
162 return cht_staticerr(ip, "bad IPv4 address syntax", "SOCKADDR SYNTAX IPV4");
165 if (!strcmp(comma,"*")) {
168 errno=0; port_l=strtoul(comma,&ep,10);
170 return cht_staticerr(ip, "bad IPv4 port", "SOCKADDR SYNTAX IPV4");
172 return cht_staticerr(ip, "IPv4 port out of range", "SOCKADDR SYNTAX IPV4");
173 s.sin.sin_port= htons(port_l);
178 return cht_staticerr(ip, "bad socket address syntax", "SOCKADDR SYNTAX OTHER");
182 cht_sockaddr_create(OBJ_SOCKADDR(o), (void*)&s, sl);
184 o->typePtr = &sockaddr_type;
188 Tcl_ObjType sockaddr_type = {
190 sockaddr_t_free, sockaddr_t_dup, sockaddr_t_ustr, sockaddr_t_sfa